From 6a86c7c5c90c3452e8a85141b87bdffec40dd914 Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sun, 26 Feb 2006 20:46:11 +0000
Subject: [PATCH] Add SNMP support (bug #6439)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@11193 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 configs/res_snmp.conf.sample |  10 +
 doc/asterisk-mib.txt         | 717 +++++++++++++++++++++++++++++
 doc/digium-mib.txt           |  17 +
 doc/snmp.txt                 |  36 ++
 res/Makefile                 |   8 +
 res/res_snmp.c               | 148 ++++++
 res/snmp/agent.c             | 845 +++++++++++++++++++++++++++++++++++
 res/snmp/agent.h             |  40 ++
 8 files changed, 1821 insertions(+)
 create mode 100644 configs/res_snmp.conf.sample
 create mode 100644 doc/asterisk-mib.txt
 create mode 100644 doc/digium-mib.txt
 create mode 100644 doc/snmp.txt
 create mode 100644 res/res_snmp.c
 create mode 100644 res/snmp/agent.c
 create mode 100644 res/snmp/agent.h

diff --git a/configs/res_snmp.conf.sample b/configs/res_snmp.conf.sample
new file mode 100644
index 0000000000..5ca09d5761
--- /dev/null
+++ b/configs/res_snmp.conf.sample
@@ -0,0 +1,10 @@
+;
+; Configuration file for res_snmp
+;
+
+[general]
+; We run as a subagent per default -- to run as a full agent
+; we must run as root (to be able to bind to port 161) 
+;subagent = yes
+; SNMP must be explicitly enabled to be active
+;enabled = yes
diff --git a/doc/asterisk-mib.txt b/doc/asterisk-mib.txt
new file mode 100644
index 0000000000..f4d6656f95
--- /dev/null
+++ b/doc/asterisk-mib.txt
@@ -0,0 +1,717 @@
+ASTERISK-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+	OBJECT-TYPE, MODULE-IDENTITY, Integer32, Counter32, TimeTicks
+		FROM SNMPv2-SMI
+
+	TEXTUAL-CONVENTION, DisplayString, TruthValue
+		FROM SNMPv2-TC
+
+	digium
+		FROM DIGIUM-MIB;
+
+asterisk MODULE-IDENTITY
+	LAST-UPDATED	"200602041900Z"
+	ORGANIZATION	"Digium, Inc."
+	CONTACT-INFO
+		"Mark Spencer
+		Email: markster@digium.com"
+	DESCRIPTION
+		"Asterisk is an Open Source PBX.  This MIB defined
+		objects for managing Asterisk instances."
+	::= { digium 1 }
+
+asteriskVersion		OBJECT IDENTIFIER ::= { asterisk 1 }
+asteriskConfiguration	OBJECT IDENTIFIER ::= { asterisk 2 }
+asteriskModules		OBJECT IDENTIFIER ::= { asterisk 3 }
+asteriskIndications	OBJECT IDENTIFIER ::= { asterisk 4 }
+asteriskChannels	OBJECT IDENTIFIER ::= { asterisk 5 }
+
+-- asteriskVersion
+
+astVersionString OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Text version string of the version of Asterisk that
+		the SNMP Agent was compiled to run against."
+	::= { asteriskVersion 1 }
+
+astVersionTag OBJECT-TYPE
+	SYNTAX		Unsigned32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"SubVersion revision of the version of Asterisk that
+		the SNMP Agent was compiled to run against -- this is
+		typically 0 for release-versions of Asterisk."
+	::= { asteriskVersion 2 }
+
+-- asteriskConfiguration
+
+astConfigUpTime OBJECT-TYPE
+	SYNTAX		TimeTicks
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Time ticks since Asterisk was started."
+	::= { asteriskConfiguration 1 }
+
+astConfigReloadTime OBJECT-TYPE
+	SYNTAX		TimeTicks
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Time ticks since Asterisk was last reloaded."
+	::= { asteriskConfiguration 2 }
+
+astConfigPid OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"The process id of the running Asterisk process."
+	::= { asteriskConfiguration 3 }
+
+astConfigSocket OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"The control socket for giving Asterisk commands."
+	::= { asteriskConfiguration 4 }
+
+-- asteriskModules
+
+astNumModules OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Number of modules currently loaded into Asterisk."
+	::= { asteriskModules 1 }
+
+-- asteriskIndications
+
+astNumIndications OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Number of indications currently defined in Asterisk."
+	::= { asteriskIndications 1 }
+
+astCurrentIndication OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Default indication zone to use."
+	::= { asteriskIndications 2 }
+
+astIndicationsTable OBJECT-TYPE
+	SYNTAX		SEQUENCE OF AstIndicationsEntry
+	MAX-ACCESS	not-accessible
+	STATUS		current
+	DESCRIPTION
+		"Table with all the indication zones currently know to
+		the running Asterisk instance."
+	::= { asteriskIndications 3 }
+
+astIndicationsEntry OBJECT-TYPE
+	SYNTAX		AstIndicationsEntry
+	MAX-ACCESS	not-accessible
+	STATUS		current
+	DESCRIPTION
+		"Information about a single indication zone."
+	INDEX		{ astIndIndex }
+	::= { astIndicationsTable 1 }
+
+AstIndicationsEntry ::= SEQUENCE {
+	astIndIndex		Integer32,
+	astIndCountry		DisplayString,
+	astIndAlias		DisplayString,
+	astIndDescription	DisplayString
+}
+
+astIndIndex OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Numerical index into the table of indication zones."
+	::= { astIndicationsEntry 1 }
+
+astIndCountry OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Country for which the indication zone is valid,
+		typically this is the ISO 2-letter code of the country."
+	::= { astIndicationsEntry 2 }
+
+astIndAlias OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		""
+	::= { astIndicationsEntry 3 }
+
+astIndDescription OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Description of the indication zone, usually the full
+		name of the country it is valid for."
+	::= { astIndicationsEntry 4 }
+
+-- asteriskChannels
+
+astNumChannels OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current number of active channels."
+	::= { asteriskChannels 1 }
+
+astChanTable OBJECT-TYPE
+	SYNTAX		SEQUENCE OF AstChanEntry
+	MAX-ACCESS	not-accessible
+	STATUS		current
+	DESCRIPTION
+		"Table with details of the currently active channels
+		in the Asterisk instance."
+	::= { asteriskChannels 2 }
+
+astChanEntry OBJECT-TYPE
+	SYNTAX		AstChanEntry
+	MAX-ACCESS	not-accessible
+	STATUS		current
+	DESCRIPTION
+		"Details of a single channel."
+	INDEX		{ astChanIndex }
+	::= { astChanTable 1 }
+
+AstChanEntry ::= SEQUENCE {
+	astChanIndex		Integer32,
+	astChanName		DisplayString,
+	astChanLanguage		DisplayString,
+	astChanType		DisplayString,
+	astChanMusicClass	DisplayString,
+	astChanBridge		DisplayString,
+	astChanMasq		DisplayString,
+	astChanMasqr		DisplayString,
+	astChanWhenHangup	TimeTicks,
+	astChanApp		DisplayString,
+	astChanData		DisplayString,
+	astChanContext		DisplayString,
+	astChanMacroContext	DisplayString,
+	astChanMacroExten	DisplayString,
+	astChanMacroPri		Integer32,
+	astChanExten		DisplayString,
+	astChanPri		Integer32,
+	astChanAccountCode	DisplayString,
+	astChanForwardTo	DisplayString,
+	astChanUniqueId		DisplayString,
+	astChanCallGroup	Unsigned32,
+	astChanPickupGroup	Unsigned32,
+	astChanState		INTEGER,
+	astChanMuted		TruthValue,
+	astChanRings		Integer32,
+	astChanCidDNID		DisplayString,
+	astChanCidNum		DisplayString,
+	astChanCidName		DisplayString,
+	astChanCidANI		DisplayString,
+	astChanCidRDNIS		DisplayString,
+	astChanCidPresentation	DisplayString,
+	astChanCidANI2		Integer32,
+	astChanCidTON		Integer32,
+	astChanCidTNS		Integer32,
+	astChanAMAFlags		INTEGER,
+	astChanADSI		INTEGER,
+	astChanToneZone		DisplayString,
+	astChanHangupCause	INTEGER,
+	astChanVariables	DisplayString,
+	astChanFlags		BITS,
+	astChanTransferCap	INTEGER
+}
+
+astChanIndex OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Index into the channel table."
+	::= { astChanEntry 1 }
+
+astChanName OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Name of the currentl channel."
+	::= { astChanEntry 2 }
+
+astChanLanguage OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Which language the current channel is configured to
+		use -- used mainly for prompts."
+	::= { astChanEntry 3 }
+
+astChanType OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Underlying technology for the current channel."
+	::= { astChanEntry 4 }
+
+astChanMusicClass OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Music class to be used for Music on Hold for this
+		channel."
+	::= { astChanEntry 5 }
+
+astChanBridge OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Which channel this channel is currently bridged (in a
+		conversation) with."
+	::= { astChanEntry 6 }
+
+astChanMasq OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Channel masquerading for us."
+	::= { astChanEntry 7 }
+
+astChanMasqr OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Channel we are masquerading for."
+	::= { astChanEntry 8 }
+
+astChanWhenHangup OBJECT-TYPE
+	SYNTAX		TimeTicks
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"How long until this channel will be hung up."
+	::= { astChanEntry 9 }
+
+astChanApp OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current application for the channel."
+	::= { astChanEntry 10 }
+
+astChanData OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Arguments passed to the current application."
+	::= { astChanEntry 11 }
+
+astChanContext OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current extension context."
+	::= { astChanEntry 12 }
+
+astChanMacroContext OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current macro context."
+	::= { astChanEntry 13 }
+
+astChanMacroExten OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current macro extension."
+	::= { astChanEntry 14 }
+
+astChanMacroPri OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current macro priority."
+	::= { astChanEntry 15 }
+
+astChanExten OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current extension."
+	::= { astChanEntry 16 }
+
+astChanPri OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Current priority."
+	::= { astChanEntry 17 }
+
+astChanAccountCode OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Account Code for billing."
+	::= { astChanEntry 18 }
+
+astChanForwardTo OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Where to forward to if asked to dial on this
+		interface."
+	::= { astChanEntry 19 }
+
+astChanUniqueId OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Unique Channel Identifier."
+	::= { astChanEntry 20 }
+
+astChanCallGroup OBJECT-TYPE
+	SYNTAX		Unsigned32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Call Group."
+	::= { astChanEntry 21 }
+
+astChanPickupGroup OBJECT-TYPE
+	SYNTAX		Unsigned32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Pickup Group."
+	::= { astChanEntry 22 }
+
+astChanState OBJECT-TYPE
+	SYNTAX		INTEGER {
+		stateDown(0),
+		stateReserved(1),
+		stateOffHook(2),
+		stateDialing(3),
+		stateRing(4),
+		stateRinging(5),
+		stateUp(6),
+		stateBusy(7),
+		stateDialingOffHook(8),
+		statePreRing(9)
+	}
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Channel state."
+	::= { astChanEntry 23 }
+
+astChanMuted OBJECT-TYPE
+	SYNTAX		TruthValue
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Transmission of voice data has been muted."
+	::= { astChanEntry 24 }
+
+astChanRings OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Number of rings so far."
+	::= { astChanEntry 25 }
+
+astChanCidDNID OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Dialled Number ID."
+	::= { astChanEntry 26 }
+
+astChanCidNum OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Caller Number."
+	::= { astChanEntry 27 }
+
+astChanCidName OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Caller Name."
+	::= { astChanEntry 28 }
+
+astCanCidANI OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"ANI"
+	::= { astChanEntry 29 }
+
+astChanCidRDNIS OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Redirected Dialled Number Service."
+	::= { astChanEntry 30 }
+
+astChanCidPresentation OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Number Presentation/Screening."
+	::= { astChanEntry 31 }
+
+astChanCidANI2 OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"ANI 2 (info digit)."
+	::= { astChanEntry 32 }
+
+astChanCidTON OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Type of Number."
+	::= { astChanEntry 33 }
+
+astChanCidTNS OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Transit Network Select."
+	::= { astChanEntry 34 }
+
+astChanAMAFlags OBJECT-TYPE
+	SYNTAX		INTEGER {
+		Default(0),
+		Omit(1),
+		Billing(2),
+		Documentation(3)
+	}
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"AMA Flags."
+	::= { astChanEntry 35 }
+
+astChanADSI OBJECT-TYPE
+	SYNTAX		INTEGER {
+		Unknown(0),
+		Available(1),
+		Unavailable(2),
+		OffHookOnly(3)
+	}
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Whether or not ADSI is detected on CPE."
+	::= { astChanEntry 36 }
+
+astChanToneZone OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Indication zone to use for channel."
+	::= { astChanEntry 37 }
+
+astChanHangupCause OBJECT-TYPE
+	SYNTAX		INTEGER {
+		NotDefined(0),
+		Unregistered(3),
+		Normal(16),
+		Busy(17),
+		NoAnswer(19),
+		Congestion(34),
+		Failure(38),
+		NoSuchDriver(66)
+	}
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Why is the channel hung up."
+	::= { astChanEntry 38 }
+
+astChanVariables OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Channel Variables defined for this channel."
+	::= { astChanEntry 39 }
+
+astChanFlags OBJECT-TYPE
+	SYNTAX		BITS {
+		WantsJitter(0),
+		DeferDTMF(1),
+		WriteInterrupt(2),
+		Blocking(3),
+		Zombie(4),
+		Exception(5),
+		MusicOnHold(6),
+		Spying(7),
+		NativeBridge(8),
+		AutoIncrementingLoop(9)
+	}
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Flags set on this channel."
+	::= { astChanEntry 40 }
+
+astChanTransferCap OBJECT-TYPE
+	SYNTAX		INTEGER {
+		Speech(0),
+		Digital(8),
+		RestrictedDigital(9),
+		3kAudio(16),
+		DigitalWithTones(17),
+		Video(24)
+	}
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Transfer Capabilities for this channel."
+	::= { astChanEntry 41 }
+
+astNumChanTypes OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Number of channel types (technologies) supported."
+	::= { asteriskChannels 3 }
+
+astChanTypeTable OBJECT-TYPE
+	SYNTAX		SEQUENCE OF AstChanTypeEntry
+	MAX-ACCESS	not-accessible
+	STATUS		current
+	DESCRIPTION
+		"Table with details of the supported channel types."
+	::= { asteriskChannels 4 }
+
+astChanTypeEntry OBJECT-TYPE
+	SYNTAX		AstChanTypeEntry
+	MAX-ACCESS	not-accessible
+	STATUS		current
+	DESCRIPTION
+		"Information about a technology we support, including
+		how many channels are currently using this technology."
+	INDEX		{ astChanTypeIndex }
+	::= { astChanTypeTable 1 }
+
+AstChanTypeEntry ::= SEQUENCE {
+	astChanTypeIndex	Integer32,
+	astChanTypeName		DisplayString,
+	astChanTypeDesc		DisplayString,
+	astChanTypeDeviceState	Integer32,
+	astChanTypeIndications	Integer32,
+	astChanTypeTransfer	Integer32,
+	astChanTypeChannels	Gauge32
+}
+
+astChanTypeIndex OBJECT-TYPE
+	SYNTAX		Integer32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Index into the table of channel types."
+	::= { astChanTypeEntry 1 }
+
+astChanTypeName OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Unique name of the technology we are describing."
+	::= { astChanTypeEntry 2 }
+
+astChanTypeDesc OBJECT-TYPE
+	SYNTAX		DisplayString
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Description of the channel type (technology)."
+	::= { astChanTypeEntry 3 }
+
+astChanTypeDeviceState OBJECT-TYPE
+	SYNTAX		TruthValue
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Whether the current technology can hold device states."
+	::= { astChanTypeEntry 4 }
+
+astChanTypeIndications OBJECT-TYPE
+	SYNTAX		TruthValue
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Whether the current technology supports progress indication."
+	::= { astChanTypeEntry 5 }
+
+astChanTypeTransfer OBJECT-TYPE
+	SYNTAX		TruthValue
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Whether the current technology supports transfers, where
+		Asterisk can get out from inbetween two bridged channels."
+	::= { astChanTypeEntry 6 }
+
+astChanTypeChannels OBJECT-TYPE
+	SYNTAX		Gauge32
+	MAX-ACCESS	read-only
+	STATUS		current
+	DESCRIPTION
+		"Number of active channels using the current technology."
+	::= { astChanTypeEntry 7 }
+
+END
diff --git a/doc/digium-mib.txt b/doc/digium-mib.txt
new file mode 100644
index 0000000000..018a080dd3
--- /dev/null
+++ b/doc/digium-mib.txt
@@ -0,0 +1,17 @@
+DIGIUM-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+	enterprises
+		FROM SNMPv2-SMI;
+
+digium MODULE-IDENTITY
+	LAST-UPDATED	"200602041900Z"
+	ORGANIZATION	"Digium, Inc."
+	CONTACT-INFO
+		"Mark Spencer
+		Email: markster@digium.com"
+	DESCRIPTION
+		""
+	::= { enterprises 22736 }
+
+END
diff --git a/doc/snmp.txt b/doc/snmp.txt
new file mode 100644
index 0000000000..afab91c3e0
--- /dev/null
+++ b/doc/snmp.txt
@@ -0,0 +1,36 @@
+Asterisk SNMP Support
+---------------------
+
+Rudimentary support for SNMP access to Asterisk is available.  To build
+this, one needs to have Net-SNMP development headers and libraries on
+the build system, including any libraries Net-SNMP depends on.
+
+Note that on some (many?) Linux-distributions the dependency list in
+the net-snmp-devel list is not complete, and additional RPMs will need
+to be installed.  This is typically seen as attempts to build res_snmp
+as net-snmp-devel is available, but then failures to find certain
+libraries.
+
+SNMP support comes in two varieties -- as a sub-agent to a running SNMP
+daemon using the AgentX protocol, or as a full standalone agent.  If
+you wish to run a full standalone agent, Asterisk must run as root in
+order to find to port 161.
+
+Configuring access when running as a full agent is something that is
+left as an exercise to the reader.
+
+To enable access to the Asterisk SNMP subagent from a master SNMP
+daemon, one will need to enable AgentX support, and also make sure that
+Asterisk will be able to access the Unix domain socket.  One way of
+doing this is to add the following to /etc/snmp/snmpd.conf:
+
+	# Enable AgentX support
+	master agentx
+
+	# Set permissions on AgentX socket and containing
+	# directory such that process in group 'asterisk'
+	# will be able to connect
+	agentXPerms  0660 0550 nobody asterisk
+
+This assumes that you run Asterisk under group 'asterisk' (and does
+not care what user you run as).
diff --git a/res/Makefile b/res/Makefile
index 2759f4e49e..08ee8e14a3 100644
--- a/res/Makefile
+++ b/res/Makefile
@@ -32,6 +32,11 @@ ifeq (${OSPLIB},)
   MODS:=$(filter-out res_osp.so,$(MODS))
 endif
 
+ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/net-snmp/net-snmp-config.h),)
+	SNMP_LDLIBS+=$(shell net-snmp-config --agent-libs)
+	MODS+=res_snmp.so
+endif
+
 ifeq (${WITH_SMDI},)
   MODS:=$(filter-out res_smdi.so,$(MODS))
 endif
@@ -108,6 +113,9 @@ res_features.so: res_features.o
 res_config_odbc.so: res_config_odbc.o
 	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${CYG_RES_CONFIG_ODBC_LIB}
 
+res_snmp.so: res_snmp.o snmp/agent.o
+	$(CC) $(SOLINK) ${SNMP_LDFLAGS} -o $@ ${CYGSOLINK} res_snmp.o snmp/agent.o ${CYGSOLIB} ${SNMP_LDLIBS}
+
 ifneq ($(wildcard .depend),)
   include .depend
 endif
diff --git a/res/res_snmp.c b/res/res_snmp.c
new file mode 100644
index 0000000000..e62e6fb05d
--- /dev/null
+++ b/res/res_snmp.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2006 Voop as
+ * Thorsten Lockert <tholo@voop.as>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief SNMP Agent / SubAgent support for Asterisk
+ *
+ * \author Thorsten Lockert <tholo@voop.as>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/options.h"
+
+#include "snmp/agent.h"
+
+#define	MODULE_DESCRIPTION	"SNMP [Sub]Agent for Asterisk"
+
+int res_snmp_agentx_subagent;
+int res_snmp_dont_stop;
+int res_snmp_enabled;
+
+static pthread_t thread;
+
+static int load_config(void)
+{
+    struct ast_variable *var;
+    struct ast_config *cfg;
+    char *cat;
+	
+	res_snmp_enabled = 0;
+	res_snmp_agentx_subagent = 1;
+    cfg = ast_config_load("res_snmp.conf");
+    if (cfg) {
+		cat = ast_category_browse(cfg, NULL);
+		while (cat) {
+			var = ast_variable_browse(cfg, cat);
+
+			if (strcasecmp(cat, "general") == 0) {
+				while (var) {
+					if (strcasecmp(var->name, "subagent") == 0) {
+						if (ast_true(var->value))
+							res_snmp_agentx_subagent = 1;
+						else if (ast_false(var->value))
+							res_snmp_agentx_subagent = 0;
+						else {
+							ast_log(LOG_ERROR, "Value '%s' does not evaluate to true or false.\n",
+									var->value);
+							ast_config_destroy(cfg);
+							return 1;
+						}
+					} else if (strcasecmp(var->name, "enabled") == 0) {
+						res_snmp_enabled = ast_true(var->value);
+					} else {
+						ast_log(LOG_ERROR, "Unrecognized variable '%s' in category '%s'\n",
+								var->name, cat);
+						ast_config_destroy(cfg);
+						return 1;
+					}
+					var = var->next;
+				}
+			}
+			else {
+				ast_log(LOG_ERROR, "Unrecognized category '%s'\n", cat);
+				ast_config_destroy(cfg);
+				return 1;
+			}
+
+			cat = ast_category_browse(cfg, cat);
+		}
+		ast_config_destroy(cfg);
+    }
+
+    return 0;
+}
+
+int load_module(void)
+{
+    load_config();
+
+    ast_verbose(VERBOSE_PREFIX_1 "Loading [Sub]Agent Module\n");
+
+    res_snmp_dont_stop = 1;
+	if (res_snmp_enabled)
+	    return ast_pthread_create(&thread, NULL, agent_thread, NULL);
+	else
+		return 0;
+}
+
+int unload_module(void)
+{
+    ast_verbose(VERBOSE_PREFIX_1 "Unloading [Sub]Agent Module\n");
+
+    res_snmp_dont_stop = 0;
+    return pthread_join(thread, NULL);
+}
+
+int reload(void)
+{
+    ast_verbose(VERBOSE_PREFIX_1 "Reloading [Sub]Agent Module\n");
+
+    res_snmp_dont_stop = 0;
+    pthread_join(thread, NULL);
+
+    load_config();
+
+    res_snmp_dont_stop = 1;
+	if (res_snmp_enabled)
+	    return ast_pthread_create(&thread, NULL, agent_thread, NULL);
+	else
+		return 0;
+}
+
+int usecount(void)
+{
+    return 0;
+}
+
+char *key(void)
+{
+    return ASTERISK_GPL_KEY;
+}
+
+char *description(void)
+{
+    return MODULE_DESCRIPTION;
+}
+
+/*
+ * Local Variables:
+ * c-file-style: gnu
+ * c-basic-offset: 4
+ * c-file-offsets: ((case-label . 0))
+ * tab-width: 4
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/res/snmp/agent.c b/res/snmp/agent.c
new file mode 100644
index 0000000000..740f5c10e1
--- /dev/null
+++ b/res/snmp/agent.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (C) 2006 Voop as
+ * Thorsten Lockert <tholo@voop.as>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief SNMP Agent / SubAgent support for Asterisk
+ *
+ * \author Thorsten Lockert <tholo@voop.as>
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/*
+ * These conflict with ones in Asterisk header files, so
+ * get rid of  them.  They'll be back after the next few
+ * includes...
+ */
+#undef HAVE_GETLOADAVG
+#undef HAVE_STRCASESTR
+
+#include <pthread.h>
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/logger.h"
+#include "asterisk/options.h"
+#include "asterisk/indications.h"
+#include "asterisk/version.h"
+#include "asterisk/pbx.h"
+
+/* Colission between Net-SNMP and Asterisk */
+#define unload_module ast_unload_module
+#include "asterisk/module.h"
+#undef unload_module
+
+#include "agent.h"
+
+/* Helper functions in Net-SNMP, header file not installed by default */
+int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);
+int header_simple_table(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **, int);
+int register_sysORTable(oid *, size_t, const char *);
+int unregister_sysORTable(oid *, size_t);
+
+/* Not defined in header files */
+extern char ast_config_AST_SOCKET[];
+
+/* Forward declaration */
+static void init_asterisk_mib(void);
+
+/*
+ * Anchor for all the Asterisk MIB values
+ */
+static oid asterisk_oid[] = { 1, 3, 6, 1, 4, 1, 22736, 1 };
+
+/*
+ * MIB values -- these correspond to values in the Asterisk MIB,
+ * and MUST be kept in sync with the MIB for things to work as
+ * expected.
+ */
+#define ASTVERSION				1
+#define		ASTVERSTRING			1
+#define		ASTVERTAG				2
+
+#define	ASTCONFIGURATION		2
+#define		ASTCONFUPTIME			1
+#define		ASTCONFRELOADTIME		2
+#define		ASTCONFPID				3
+#define		ASTCONFSOCKET			4
+
+#define	ASTMODULES				3
+#define		ASTMODCOUNT				1
+
+#define	ASTINDICATIONS			4
+#define		ASTINDCOUNT				1
+#define		ASTINDCURRENT			2
+
+#define		ASTINDTABLE				3
+#define			ASTINDINDEX				1
+#define			ASTINDCOUNTRY			2
+#define			ASTINDALIAS				3
+#define			ASTINDDESCRIPTION		4
+
+#define	ASTCHANNELS				5
+#define		ASTCHANCOUNT			1
+
+#define		ASTCHANTABLE			2
+#define			ASTCHANINDEX			1
+#define			ASTCHANNAME				2
+#define			ASTCHANLANGUAGE			3
+#define			ASTCHANTYPE				4
+#define			ASTCHANMUSICCLASS		5
+#define			ASTCHANBRIDGE			6
+#define			ASTCHANMASQ				7
+#define			ASTCHANMASQR			8
+#define			ASTCHANWHENHANGUP		9
+#define			ASTCHANAPP				10
+#define			ASTCHANDATA				11
+#define			ASTCHANCONTEXT			12
+#define			ASTCHANMACROCONTEXT		13
+#define			ASTCHANMACROEXTEN		14
+#define			ASTCHANMACROPRI			15
+#define			ASTCHANEXTEN			16
+#define			ASTCHANPRI				17
+#define			ASTCHANACCOUNTCODE		18
+#define			ASTCHANFORWARDTO		19
+#define			ASTCHANUNIQUEID			20
+#define			ASTCHANCALLGROUP		21
+#define			ASTCHANPICKUPGROUP		22
+#define			ASTCHANSTATE			23
+#define			ASTCHANMUTED			24
+#define			ASTCHANRINGS			25
+#define			ASTCHANCIDDNID			26
+#define			ASTCHANCIDNUM			27
+#define			ASTCHANCIDNAME			28
+#define			ASTCHANCIDANI			29
+#define			ASTCHANCIDRDNIS			30
+#define			ASTCHANCIDPRES			31
+#define			ASTCHANCIDANI2			32
+#define			ASTCHANCIDTON			33
+#define			ASTCHANCIDTNS			34
+#define			ASTCHANAMAFLAGS			35
+#define			ASTCHANADSI				36
+#define			ASTCHANTONEZONE			37
+#define			ASTCHANHANGUPCAUSE		38
+#define			ASTCHANVARIABLES		39
+#define			ASTCHANFLAGS			40
+#define			ASTCHANTRANSFERCAP		41
+
+#define		ASTCHANTYPECOUNT		3
+
+#define		ASTCHANTYPETABLE		4
+#define			ASTCHANTYPEINDEX		1
+#define			ASTCHANTYPENAME			2
+#define			ASTCHANTYPEDESC			3
+#define			ASTCHANTYPEDEVSTATE		4
+#define			ASTCHANTYPEINDICATIONS	5
+#define			ASTCHANTYPETRANSFER		6
+#define			ASTCHANTYPECHANNELS		7
+
+void *agent_thread(void *arg)
+{
+    ast_verbose(VERBOSE_PREFIX_2 "Starting %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
+
+    snmp_enable_stderrlog();
+
+    if (res_snmp_agentx_subagent)
+		netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
+							   NETSNMP_DS_AGENT_ROLE,
+							   1);
+
+    init_agent("asterisk");
+
+    init_asterisk_mib();
+
+    init_snmp("asterisk");
+
+    if (!res_snmp_agentx_subagent)
+		init_master_agent();
+
+    while (res_snmp_dont_stop)
+		agent_check_and_process(1);
+
+    snmp_shutdown("asterisk");
+
+    ast_verbose(VERBOSE_PREFIX_2 "Terminating %sAgent\n",
+				res_snmp_agentx_subagent ? "Sub" : "");
+
+    return NULL;
+}
+
+static u_char *
+ast_var_channels(struct variable *vp, oid *name, size_t *length,
+				 int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+
+    if (header_generic(vp, name, length, exact, var_len, write_method))
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTCHANCOUNT:
+		long_ret = ast_active_channels();
+		return (u_char *)&long_ret;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
+									int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+    static u_char bits_ret[2];
+    static char string_ret[256];
+    struct ast_channel *chan, *bridge;
+    struct timeval tval;
+    u_char *ret;
+    int i, bit;
+
+    if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
+		return NULL;
+
+    i = name[*length - 1] - 1;
+    for (chan = ast_channel_walk_locked(NULL);
+		 chan && i;
+		 chan = ast_channel_walk_locked(chan), i--)
+		ast_mutex_unlock(&chan->lock);
+    if (chan == NULL)
+		return NULL;
+	*var_len = sizeof(long_ret);
+
+    switch (vp->magic) {
+	case ASTCHANINDEX:
+		long_ret = name[*length - 1];
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANNAME:
+		if (!ast_strlen_zero(chan->name)) {
+			strncpy(string_ret, chan->name, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANLANGUAGE:
+		if (!ast_strlen_zero(chan->language)) {
+			strncpy(string_ret, chan->language, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANTYPE:
+		strncpy(string_ret, chan->tech->type, sizeof(string_ret));
+		string_ret[sizeof(string_ret) - 1] = '\0';
+		*var_len = strlen(string_ret);
+		ret = (u_char *)string_ret;
+		break;
+	case ASTCHANMUSICCLASS:
+		if (!ast_strlen_zero(chan->musicclass)) {
+			strncpy(string_ret, chan->musicclass, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANBRIDGE:
+		if ((bridge = ast_bridged_channel(chan)) != NULL) {
+			strncpy(string_ret, bridge->name, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANMASQ:
+		if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
+			strncpy(string_ret, chan->masq->name, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANMASQR:
+		if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
+			strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANWHENHANGUP:
+		if (chan->whentohangup) {
+			gettimeofday(&tval, NULL);
+			long_ret = difftime(chan->whentohangup, tval.tv_sec) * 100 - tval.tv_usec / 10000;
+			ret= (u_char *)&long_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANAPP:
+		if (chan->appl) {
+			strncpy(string_ret, chan->appl, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANDATA:
+		if (chan->data) {
+			strncpy(string_ret, chan->data, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANCONTEXT:
+		strncpy(string_ret, chan->context, sizeof(string_ret));
+		string_ret[sizeof(string_ret) - 1] = '\0';
+		*var_len = strlen(string_ret);
+		ret = (u_char *)string_ret;
+		break;
+	case ASTCHANMACROCONTEXT:
+		strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
+		string_ret[sizeof(string_ret) - 1] = '\0';
+		*var_len = strlen(string_ret);
+		ret = (u_char *)string_ret;
+		break;
+	case ASTCHANMACROEXTEN:
+		strncpy(string_ret, chan->macroexten, sizeof(string_ret));
+		string_ret[sizeof(string_ret) - 1] = '\0';
+		*var_len = strlen(string_ret);
+		ret = (u_char *)string_ret;
+		break;
+	case ASTCHANMACROPRI:
+		long_ret = chan->macropriority;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANEXTEN:
+		strncpy(string_ret, chan->exten, sizeof(string_ret));
+		string_ret[sizeof(string_ret) - 1] = '\0';
+		*var_len = strlen(string_ret);
+		ret = (u_char *)string_ret;
+		break;
+	case ASTCHANPRI:
+		long_ret = chan->priority;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANACCOUNTCODE:
+		if (!ast_strlen_zero(chan->accountcode)) {
+			strncpy(string_ret, chan->accountcode, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANFORWARDTO:
+		if (!ast_strlen_zero(chan->call_forward)) {
+			strncpy(string_ret, chan->call_forward, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANUNIQUEID:
+		strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
+		string_ret[sizeof(string_ret) - 1] = '\0';
+		*var_len = strlen(string_ret);
+		ret = (u_char *)string_ret;
+		break;
+	case ASTCHANCALLGROUP:
+		long_ret = chan->callgroup;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANPICKUPGROUP:
+		long_ret = chan->pickupgroup;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANSTATE:
+		long_ret = chan->_state & 0xffff;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANMUTED:
+		long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANRINGS:
+		long_ret = chan->rings;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANCIDDNID:
+		if (chan->cid.cid_dnid) {
+			strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANCIDNUM:
+		if (chan->cid.cid_num) {
+			strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANCIDNAME:
+		if (chan->cid.cid_name) {
+			strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANCIDANI:
+		if (chan->cid.cid_ani) {
+			strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANCIDRDNIS:
+		if (chan->cid.cid_rdnis) {
+			strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANCIDPRES:
+		long_ret = chan->cid.cid_pres;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANCIDANI2:
+		long_ret = chan->cid.cid_ani2;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANCIDTON:
+		long_ret = chan->cid.cid_ton;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANCIDTNS:
+		long_ret = chan->cid.cid_tns;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANAMAFLAGS:
+		long_ret = chan->amaflags;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANADSI:
+		long_ret = chan->adsicpe;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANTONEZONE:
+		if (chan->zone) {
+			strncpy(string_ret, chan->zone->country, sizeof(string_ret));
+			string_ret[sizeof(string_ret) - 1] = '\0';
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANHANGUPCAUSE:
+		long_ret = chan->hangupcause;
+		ret = (u_char *)&long_ret;
+		break;
+	case ASTCHANVARIABLES:
+		if (pbx_builtin_serialize_variables(chan, string_ret, sizeof(string_ret))) {
+			*var_len = strlen(string_ret);
+			ret = (u_char *)string_ret;
+		}
+		else
+			ret = NULL;
+		break;
+	case ASTCHANFLAGS:
+		bits_ret[0] = 0;
+		for (bit = 0; bit < 8; bit++)
+			bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
+		bits_ret[1] = 0;
+		for (bit = 0; bit < 8; bit++)
+			bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
+		*var_len = 2;
+		ret = bits_ret;
+		break;
+	case ASTCHANTRANSFERCAP:
+		long_ret = chan->transfercapability;
+		ret = (u_char *)&long_ret;
+		break;
+	default:
+		ret = NULL;
+		break;
+    }
+    ast_mutex_unlock(&chan->lock);
+    return ret;
+}
+
+static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
+								   int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+	struct ast_variable *channel_types, *next;
+
+    if (header_generic(vp, name, length, exact, var_len, write_method))
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTCHANTYPECOUNT:
+		long_ret = 0;
+		for (channel_types = next = ast_channeltype_list(); next; next = next->next) {
+			long_ret++;
+		}
+		ast_variables_destroy(channel_types);
+		return (u_char *)&long_ret;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
+										int exact, size_t *var_len, WriteMethod **write_method)
+{
+	const struct ast_channel_tech *tech = NULL;
+	struct ast_variable *channel_types, *next;
+    static unsigned long long_ret;
+    struct ast_channel *chan;
+    u_long i;
+
+    if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
+		return NULL;
+
+	channel_types = ast_channeltype_list();
+	for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
+		;
+	if (next != NULL)
+		tech = ast_get_channel_tech(next->name);
+	ast_variables_destroy(channel_types);
+    if (next == NULL || tech == NULL)
+		return NULL;
+    
+    switch (vp->magic) {
+	case ASTCHANTYPEINDEX:
+		long_ret = name[*length - 1];
+		return (u_char *)&long_ret;
+	case ASTCHANTYPENAME:
+		*var_len = strlen(tech->type);
+		return (u_char *)tech->type;
+	case ASTCHANTYPEDESC:
+		*var_len = strlen(tech->description);
+		return (u_char *)tech->description;
+	case ASTCHANTYPEDEVSTATE:
+		long_ret = tech->devicestate ? 1 : 2;
+		return (u_char *)&long_ret;
+	case ASTCHANTYPEINDICATIONS:
+		long_ret = tech->indicate ? 1 : 2;
+		return (u_char *)&long_ret;
+	case ASTCHANTYPETRANSFER:
+		long_ret = tech->transfer ? 1 : 2;
+		return (u_char *)&long_ret;
+	case ASTCHANTYPECHANNELS:
+		long_ret = 0;
+		for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
+			ast_mutex_unlock(&chan->lock);
+			if (chan->tech == tech)
+				long_ret++;
+		}
+		return (u_char *)&long_ret;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
+							 int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+    struct timeval tval;
+
+    if (header_generic(vp, name, length, exact, var_len, write_method))
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTCONFUPTIME:
+		gettimeofday(&tval, NULL);
+		long_ret = difftime(tval.tv_sec, ast_startuptime) * 100 + tval.tv_usec / 10000;
+		return (u_char *)&long_ret;
+	case ASTCONFRELOADTIME:
+		gettimeofday(&tval, NULL);
+		if (ast_lastreloadtime)
+			long_ret = difftime(tval.tv_sec, ast_lastreloadtime) * 100 + tval.tv_usec / 10000;
+		else
+			long_ret = difftime(tval.tv_sec, ast_startuptime) * 100 + tval.tv_usec / 10000;
+		return (u_char *)&long_ret;
+	case ASTCONFPID:
+		long_ret = getpid();
+		return (u_char *)&long_ret;
+	case ASTCONFSOCKET:
+		*var_len = strlen(ast_config_AST_SOCKET);
+		return (u_char *)ast_config_AST_SOCKET;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
+								  int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+    struct tone_zone *tz;
+
+    if (header_generic(vp, name, length, exact, var_len, write_method))
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTINDCOUNT:
+		if (ast_mutex_lock(&tzlock)) {
+			ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
+			snmp_log(LOG_ERR, "Unable to lock tone_zones list in ast_var_indications\n");
+			return NULL;
+		}
+		long_ret = 0;
+		for (tz = tone_zones; tz; tz = tz->next)
+			long_ret++;
+		ast_mutex_unlock(&tzlock);
+
+		return (u_char *)&long_ret;
+	case ASTINDCURRENT:
+		tz = ast_get_indication_zone(NULL);
+		if (tz) {
+			*var_len = strlen(tz->country);
+			return (u_char *)tz->country;
+		}
+		*var_len = 0;
+		return NULL;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
+									   int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+    struct tone_zone *tz;
+    int i;
+
+    if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
+		return NULL;
+
+    if (ast_mutex_lock(&tzlock)) {
+		ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
+		snmp_log(LOG_ERR, "Unable to lock tone_zones list in ast_var_indications_table\n");
+		return NULL;
+    }
+    i = name[*length - 1] - 1;
+    for (tz = tone_zones; tz && i; tz = tz->next)
+		i--;
+    ast_mutex_unlock(&tzlock);
+    if (tz == NULL)
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTINDINDEX:
+		long_ret = name[*length - 1];
+		return (u_char *)&long_ret;
+	case ASTINDCOUNTRY:
+		*var_len = strlen(tz->country);
+		return (u_char *)tz->country;
+	case ASTINDALIAS:
+		if (tz->alias) {
+			*var_len = strlen(tz->alias);
+			return (u_char *)tz->alias;
+		}
+		return NULL;
+	case ASTINDDESCRIPTION:
+		*var_len = strlen(tz->description);
+		return (u_char *)tz->description;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static int countmodule(const char *mod, const char *desc, int use, const char *like)
+{
+    return 1;
+}
+
+static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
+							  int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+
+    if (header_generic(vp, name, length, exact, var_len, write_method))
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTMODCOUNT:
+		long_ret = ast_update_module_list(countmodule, NULL);
+		return (u_char *)&long_ret;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
+							  int exact, size_t *var_len, WriteMethod **write_method)
+{
+    static unsigned long long_ret;
+
+    if (header_generic(vp, name, length, exact, var_len, write_method))
+		return NULL;
+
+    switch (vp->magic) {
+	case ASTVERSTRING:
+		*var_len = strlen(ASTERISK_VERSION);
+		return (u_char *)ASTERISK_VERSION;
+	case ASTVERTAG:
+		long_ret = ASTERISK_VERSION_NUM;
+		return (u_char *)&long_ret;
+	default:
+		break;
+    }
+    return NULL;
+}
+
+static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
+{
+    unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
+    return 0;
+}
+
+static void init_asterisk_mib(void)
+{
+    static struct variable4 asterisk_vars[] = {
+		{ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
+		{ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
+		{ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
+		{ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
+		{ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
+		{ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
+		{ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
+		{ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
+		{ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
+		{ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
+		{ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
+		{ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
+		{ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
+		{ASTCHANCOUNT,           ASN_INTEGER,   RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
+		{ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
+		{ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
+		{ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
+		{ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
+		{ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
+		{ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
+		{ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
+		{ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
+		{ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
+		{ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
+		{ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
+		{ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
+		{ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
+		{ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
+		{ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
+		{ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
+		{ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
+		{ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
+		{ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
+		{ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
+		{ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
+		{ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
+		{ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
+		{ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
+		{ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
+		{ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
+		{ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
+		{ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
+		{ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
+		{ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
+		{ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
+		{ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
+		{ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
+		{ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
+		{ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
+		{ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
+		{ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
+		{ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
+		{ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
+		{ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
+		{ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
+		{ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
+		{ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
+		{ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
+		{ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
+		{ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
+		{ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
+		{ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
+		{ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
+    };
+
+    register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
+			"ASTERISK-MIB implementation for Asterisk.");
+
+    REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
+
+    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
+			   SNMP_CALLBACK_SHUTDOWN,
+			   term_asterisk_mib, NULL);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * c-file-offsets: ((case-label . 0))
+ * tab-width: 4
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/res/snmp/agent.h b/res/snmp/agent.h
new file mode 100644
index 0000000000..21389d6c94
--- /dev/null
+++ b/res/snmp/agent.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 Voop as
+ * Thorsten Lockert <tholo@voop.as>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief SNMP Agent / SubAgent support for Asterisk
+ *
+ * \author Thorsten Lockert <tholo@voop.as>
+ */
+
+/*!
+ * \internal
+ * \brief Thread running the SNMP Agent or Subagent
+ * \param Not used -- required by pthread_create
+ * \return A pointer with return status -- not used
+ *
+ * This represent the main thread of the SNMP [sub]agent, and
+ * will initialize SNMP and loop, processing requests until
+ * termination is requested by resetting the flag in
+ * \ref res_snmp_dontStop.
+ */
+void	*agent_thread(void *);
+
+/*!
+ * \internal
+ * Flag saying whether we run as a Subagent or full Agent
+ */
+extern int res_snmp_agentx_subagent;
+
+/*!
+ * \internal
+ * Flag stating the agent thread should not terminate
+ */
+extern int res_snmp_dont_stop;
-- 
GitLab