Death: UCD-SNMP
Birth: NET-SNMP
(new agent API merged to the main branch)
git-svn-id: file:///home/hardaker/lib/sf-bkups/net-snmp-convert-svnrepo/trunk@5901 06827809-a52a-0410-b366-d66718629ded
diff --git a/agent/mibgroup/agentx/master_request.c b/agent/mibgroup/agentx/master_request.c
index f7c97a0..f46f9ec 100644
--- a/agent/mibgroup/agentx/master_request.c
+++ b/agent/mibgroup/agentx/master_request.c
@@ -55,12 +55,13 @@
#include "protocol.h"
#include "client.h"
-#include "master.h"
-#include "master_admin.h"
#include "snmp_agent.h"
+#include "agent_handler.h"
#include "snmp_vars.h"
#include "var_struct.h"
#include "mibII/sysORTable.h"
+#include "master.h"
+#include "master_admin.h"
#define VARLIST_ITERATION 10
diff --git a/agent/mibgroup/mibII/icmp.c b/agent/mibgroup/mibII/icmp.c
index d5ed42e..7057f3a 100644
--- a/agent/mibgroup/mibII/icmp.c
+++ b/agent/mibgroup/mibII/icmp.c
@@ -63,10 +63,6 @@
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif
-#if HAVE_DMALLOC_H
-#include <dmalloc.h>
-#endif
-
#include "tools.h"
#ifdef solaris2
#include "kernel_sunos5.h"
@@ -91,6 +87,10 @@
#include "icmp.h"
#include "sysORTable.h"
+#if HAVE_DMALLOC_H
+#include <dmalloc.h>
+#endif
+
#ifndef MIB_STATS_CACHE_TIMEOUT
#define MIB_STATS_CACHE_TIMEOUT 5
#endif
diff --git a/agent/mibgroup/mibII/tcpTable.c b/agent/mibgroup/mibII/tcpTable.c
index cf684fd..0e25bdf 100644
--- a/agent/mibgroup/mibII/tcpTable.c
+++ b/agent/mibgroup/mibII/tcpTable.c
@@ -115,10 +115,6 @@
#include <sys/tcpipstats.h>
#endif
-#if HAVE_DMALLOC_H
-#include <dmalloc.h>
-#endif
-
#include "auto_nlist.h"
#include "mibincl.h"
@@ -130,6 +126,10 @@
#include "tcp.h"
#include "tcpTable.h"
+#if HAVE_DMALLOC_H
+#include <dmalloc.h>
+#endif
+
/*********************
*
* Kernel & interface information,
diff --git a/agent/mibgroup/mibII/udpTable.c b/agent/mibgroup/mibII/udpTable.c
index 2805d80..6cf48e4 100644
--- a/agent/mibgroup/mibII/udpTable.c
+++ b/agent/mibgroup/mibII/udpTable.c
@@ -81,11 +81,6 @@
#include <inet/mib2.h>
#endif
-#if HAVE_DMALLOC_H
-#include <dmalloc.h>
-#endif
-
-
#ifdef solaris2
#include "kernel_sunos5.h"
#else
@@ -115,6 +110,10 @@
#include <sys/sysctl.h>
#endif
+#if HAVE_DMALLOC_H
+#include <dmalloc.h>
+#endif
+
/*********************
*
* Kernel & interface information,
diff --git a/agent/mibgroup/ucd-snmp/file.c b/agent/mibgroup/ucd-snmp/file.c
index 0da7d2b..afe1cec 100644
--- a/agent/mibgroup/ucd-snmp/file.c
+++ b/agent/mibgroup/ucd-snmp/file.c
@@ -23,9 +23,6 @@
#include <string.h>
#endif
-#if HAVE_DMALLOC_H
-#include <dmalloc.h>
-#endif
#if HAVE_STRING_H
#include <string.h>
#endif
diff --git a/local/mib2c b/local/mib2c
index 939bced..3f124ee 100755
--- a/local/mib2c
+++ b/local/mib2c
@@ -25,6 +25,7 @@
$configfile="mib2c.conf";
$debug=0;
+$quiet=0;
$nostats = 0;
sub usage {
@@ -35,6 +36,7 @@
print " mibNode\tThe name of the top level mib node you want to\n\t\tgenerate code for. By default, the code will be stored in\n\t\tmibNode.c and mibNode.h (use the -f flag to change this)\n\n";
print " -d\t\tdebugging output (dont do it. trust me.)\n\n";
print " -s\t\tDon't display statistics at the end\n\n";
+ print " -S VAR=VAL\tSet $VAR variable to $VAL\n";
1;
}
@@ -42,273 +44,248 @@
$_ = shift;
$configfile = shift if (/^-c/);
$debug = 1 if (/^-d/);
+ if (/-S/) {
+ my $expr = shift;
+ my ($var, $val) = ($expr =~ /([^=]*)=(.*)/);
+ die "no variable specified for -S flag." if (!$var);
+ $vars{$var} = $val;
+ }
+ $quiet = 1 if (/^-q/);
$nostats = 1 if (/^-s/);
usage && exit(1) if (/^-h/);
$outputName = shift if (/^-f/);
$oid = $_ if (/^[^-]/);
}
-read_config($configfile);
#
# internal conversion tables
#
-%accessToUCD = qw(ReadOnly RONLY ReadWrite RWRITE
- WriteOnly RWRITE Create RWRITE);
+%accessToIsWritable = qw(ReadOnly 0 ReadWrite 1
+ WriteOnly 1 Create 1);
+%perltoctypes = qw(OCTETSTR ASN_OCTET_STR
+ INTEGER ASN_INTEGER
+ INTEGER32 ASN_INTEGER
+ UNSIGNED32 ASN_UNSIGNED
+ OBJECTID ASN_OBJECT_ID
+ COUNTER64 ASN_COUNTER64
+ COUNTER ASN_COUNTER
+ NETADDR ASN_COUNTER
+ UINTEGER ASN_UINTEGER
+ IPADDR ASN_IPADDRESS
+ BITS ASN_IPADDRESS
+ TICKS ASN_TIMETICKS
+ GAUGE ASN_GAUGE
+ OPAQUE ASN_OPAQUE);
-# The lengths of the defined 'variableN' structures
-@varLengths = (2,4,7,8,13);
-if (!defined($oid)) {
- print STDERR "You didn\'t specify a mib oid to convert!\n";
- usage();
- exit(1);
+my $mibnode = $SNMP::MIB{$oid};
+die "you didn't give me a valid OID to start with" if (!$mibnode);
+
+# setup
+$outputName = $mibnode->{'label'} if (!defined($outputName));
+$vars{'name'} = $outputName;
+$vars{'oid'} = $oid;
+
+# loop through mib nodes, remembering stuff.
+setup_data($mibnode);
+
+# process .conf file
+$fh = new IO::File;
+$fh->open("$configfile");
+process();
+$fh->close;
+
+foreach $i (keys(%written)) {
+ next if ($i eq "-");
+ print STDERR "running indent on $i\n" if (!$quiet);
+ system("indent -orig -nbc -bap -nut $i");
}
-$mib = $SNMP::MIB{$oid};
-$_ = $commaoid = $fulloid = $mib->{'objectID'};
-if (!defined ($fulloid)) {
- print STDERR "Couldn\'t find mib reference: $oid\n";
- exit(1);
+sub tocommas {
+ my $oid = $_[0];
+ $oid =~ s/\./,/g;
+ $oid =~ s/^\s*,//;
+ return $oid;
}
-s/[^.]//g;
-$commaoid =~ s/\./,/g;
-$commaoid =~ s/^,//g;
-$outputName = $mib->{'label'} if (!defined($outputName));
-$OUTPUTNAME = uc($outputName);
-$vroutine="$outputName";
-print "outputting to $outputName.c and $outputName.h ...\n";
-
-#============================================
-#
-# Walk the MIB tree, and construct strings
-# holding the various fragments of code needed.
-#
-# 'loadMib' returns the length of the longest OID suffix
-# encountered.
-#
-# The variables constructed and used are:
-#
-# (in the header file)
-# functionInfo : A list of definitions for the table-handling functions,
-# and routines for SETtable variables.
-# (The main scalar handling routine is handled implicitly)
-#
-# (in the code file)
-# structinfo : The contents of the variableN structure listing
-# the variables handled, including type, access level,
-# OID suffix and 'magic number'
-#
-# caseStatements: A hash array (indexed by variable routine name)
-# containing the body of the switch statement
-# used for returning the appropriate values.
-# At a minimum, this consists of the various 'case' labels
-# If full type information is available (from mib2c.conf)
-# then this will also include a default initialiser,
-# and setting of a 'write_method' (if appropriate).
-#
-# writeFuncs: A list of function skeletons for setting variables
-# (for variables with suitable access levels).
-# Note that this list will not include functions
-# for variables which don't provide type information
-# in the mib2c.conf file (even if such variables are
-# defined as writeable in the variableN structure).
-#
-#============================================
-$count = 0;
-$depth = loadMib($mib,0)-1;
-
-# Determine which 'variableN' structure is needed
-for($varlen = 0; $varlen <= $#varLengths; $varlen++) {
- last if ($depth <= $varLengths[$varlen]);
+sub oidlength {
+ return scalar ($_[0] =~ /\./);
}
-$varlen = $varLengths[$varlen];
-#============================================
+# replaces $VAR type expressions and $VAR.subcomponent expressions
+# with data from the mib tree and loop variables.
+# possible uses:
#
-# Table-handling routines.
+# $var -- as defined by loops, etc.
+# ${var}otherstuff -- appending text to variable contents
+# $var.uc -- all upper case version of $var
#
-#============================================
-foreach $vtable (@table_list) {
- foreach $ptable (@processtable) {
- $variables{$ptable}{'processed'} .=
- (eval "\"$variables{$ptable}{'code'}\"") . "\n\n";
+# Mib components, $var must first expand to a mib node name:
+#
+# $var.objectID -- dotted full OID
+# $var.commaoid -- comma separated OID for array init
+# $var.subid -- last number component of oid
+# $var.oidlength -- length of the oid
+# $var.type -- node's ASN_XXX type
+# $var.settable -- 1 if it's writable, 0 if not
+# $var.access -- node's access type
+# $var.status -- node's status
+# $var.syntax -- node's syntax
+sub process_vars {
+ my $it = shift;
+
+ # mib substitutions ($var.type -> $mibnode->{'type'})
+ $it =~ s/\$(\w+)\.(uc)/uc($vars{$1})/eg; # make something uppercase
+ $it =~ s/\$(\w+)\.(commaoid)/tocommas($SNMP::MIB{$vars{$1}}{objectID})/eg; # lowercase
+ $it =~ s/\$(\w+)\.(oidlength)/oidlength($SNMP::MIB{$vars{$1}}{objectID})/eg; # lowercase
+ $it =~ s/\$(\w+)\.(perltype)/$SNMP::MIB{$vars{$1}}{type}/g; # lowercase
+ $it =~ s/\$(\w+)\.(type)/$perltoctypes{$SNMP::MIB{$vars{$1}}{$2}}/g; # lowercase
+ $it =~ s/\$(\w+)\.(subid)/$SNMP::MIB{$vars{$1}}{subID}/g; # lowercase
+ $it =~ s/\$(\w+)\.(settable)/(($SNMP::MIB{$vars{$1}}{access} =~ \/(ReadWrite|Create|Writeonly)\/)?1:0)/eg; # lowercase
+ $it =~ s/\$(\w+)\.(objectID|label|subID|access|status|syntax)/$SNMP::MIB{$vars{$1}}{$2}/g;
+
+ # normal variable substitions
+ $it =~ s/\$\{(\w+)\}/$vars{$1}/g;
+ $it =~ s/\$(\w+)/$vars{$1}/g;
+ return $it;
+}
+
+# process various types of statements
+#
+# which include:
+# @open FILE@
+# writes generated output to FILE
+# @foreach $VAR table@
+# repeat iterate over code until @end@ setting $VAR to all known tables
+# @foreach $VAR column@
+# repeat iterate over code until @end@ setting $VAR to all known
+# columns within a given table. Obviously this must be called
+# within a foreach-table clause.
+# @foreach $VAR index@
+# repeat iterate over code until @end@ setting $VAR to all known
+# indexes within a given table. Obviously this must be called
+# within a foreach-table clause.
+# @eval $VAR = expression@
+# evaluates expression and assigns the results to $VAR
+# @perleval STUFF@
+# evaluates STUFF directly in perl. Note that all mib2c variables
+# interpereted within .conf files are in $vars{NAME}.
+# @skip@
+# skips everything till the appropriately matched @end@
+# @if expression@
+# evaluates expression, and if expression is true processes
+# contained part until appropriate @end@ is reached.
+sub skippart {
+ my $endcount = 1;
+ while(<$fh>) {
+ if (/\@end\@/) {
+ return if ($endcount == 1);
+ $endcount--;
+ }
+ if (/\@else\@/) {
+ return if ($endcount == 1);
+ }
+ if (/\@(foreach|if)/) {
+ $endcount++;
+ }
}
- $var_routines .=
- (eval "\"$variables{'code-var_table'}{'code'}\"") . "\n\n";
}
-#============================================
-#
-# Output the header file
-#
-#============================================
-open(DOTH,">$outputName.h");
-print DOTH (eval "\"$variables{'code-dot-h'}{'code'}\"") . "\n";
-close(DOTH);
-#============================================
-#
-# Output the code file:
-# Initialisation and main variable routine.
-#
-#============================================
-
-open(DOTC,">$outputName.c");
-print DOTC (eval "\"$variables{'code-main-part'}{'code'}\"") . "\n\n";;
-close(DOTC);
-
-#============================================
-#
-# Everyone loves statistics.
-#
-#============================================
-print " depth: $depth\n";
-print " Number of Lines Created:\n";
-system("wc -l $outputName.c $outputName.h");
-print "Done.\n\n";
-print "NOTE: the code that has been created for you is merely a starting template.\n";
-print " You will have to modify it in order to make it work properly.\n";
-
-#============================================
-#
-# loadMib:
-# Recursive routine to walk the mib,
-# and construct the various code fragment strings.
-#
-#============================================
-sub loadMib {
- my $mib = shift;
- my $i;
- my $depth = shift;
- $depth = $depth + 1;
- my $name = $mib->{'label'};
- my $NAME = uc($name);
- print "doing $mib->{label} : $mib->{objectID}\n" if $debug;
- if (defined($mib->{'access'}) &&
- $mib->{'access'} =~ /ReadOnly|ReadWrite|WriteOnly|Create|NoAccess/) {
- $count = $count + 1;
- $subid = $mib->{'objectID'};
- $subid =~ s/$fulloid\.//;
- $subid =~ s/\./,/g;
- if (!defined($variables{$mib->{'type'}}) && !defined($mib->{'indexes'})) {
- print STDERR "unknown type: $mib->{type} for $mib->{label} $mib->{'access'}\n";
- print STDERR "unknown type: no information generated for $mib->{label}\n";
+sub process {
+ while(<$fh>) {
+ if (/^\#\#/) {
+ # noop, it's a comment
+ } elsif (/\@open\s+([^\@]+)\@/) {
+ my $spec = process_vars($1);
+ $out->close() if ($out);
+ $out = new IO::File;
+ $out->open(">$spec") || die "failed to open $spec";
+ print STDERR "writing to $spec\n" if (!$quiet);
+ $written{$spec} = '1';
+ } elsif (/\@end\@/) {
+ return;
+ } elsif (/\@if\s+([^@]*)\@/) {
+ if (eval(process_vars($1))) {
+ process();
+ } else {
+ skippart();
+ }
+ } elsif (/\@eval\s+\$(\w+)\s*=\s*([^\@]*)/) {
+ my ($v, $e) = ($1, $2);
+ my $e = process_vars($e);
+ $vars{$v} = eval($e);
+ } elsif (/\@perleval\s*(.*)\@/) {
+ eval($1);
+ } elsif (/\@skip\@/) {
+ skippart();
+ } elsif (/\@\s*foreach\s+\$([^\@]+)\s+tables*\s*\@/) {
+ my $var = $1;
+ my $startpos = tell(C);
+ my $table;
+ foreach $table (keys %tables) {
+ seek(C, $startpos, 0); # go to top of section.
+ my $oldvar = $vars{$var};
+ $vars{$var} = $table;
+ my $oldtable = $currenttable;
+ $currenttable = $table;
+ process();
+ $vars{$var} = $oldvar;
+ $currenttable = $oldtable;
+ }
+ } elsif (/\@\s*foreach\s+\$([^\@]+)\s+(column|index)\s*\@/) {
+ my ($var, $type) = ($1, $2);
+ my $startpos = $fh->tell();
+ my $column;
+ foreach $column (@{$tables{$currenttable}{$type}}) {
+# print "looping on $var for $type -> $column\n";
+ $fh->seek($startpos, 0); # go to top of section.
+ my $oldvar = $vars{$var};
+ $vars{$var} = $column;
+ my $oldcolumn = $currentcolumn;
+ $currentcolumn = $column;
+ process();
+ $vars{$var} = $oldvar;
+ $currentcolumn = $oldcolumn;
+ }
} else {
- foreach $i (@process) {
- next if (defined($variables{$i}{'skipif'}) &&
- eval $variables{$i}{'skipif'});
- my $result = (eval "\"$variables{$i}{'code'}\"");
- $variables{$i}{'processed'} .= "$result\n";
- $variables{$vroutine}{$i}{'processed'} .= "$result\n";
- }
- }
- if (defined($mib->{'indexes'})) {
- print "indexes: ", join(", ",@{$mib->{'indexes'}}),"\n" if ($debug);
- $variables{$vroutine}{'indexes'} = $mib->{'indexes'};
- foreach $i (@{$mib->{'indexes'}}) {
- $variables{$vroutine}{$i}{'isanindex'} = 1;
- }
+ die "no output file specified" if (!$out);
+ print $out process_vars($_);
}
}
- my $children = $$mib{'children'};
- my $i;
- my $newdepth = $depth;
- foreach $i (sort {$a->{subID} <=> $b->{subID}} @{$children}) {
- if ( $name =~ /Table$/ ) {
- $vroutine="$name";
- push @table_list, $name;
- $newdepth = max(loadMib($i, $depth), $newdepth);
- $vroutine="$outputName";
+}
+
+sub setup_data {
+ my $mib = shift;
+ if ($mib->{label} =~ /Table$/) {
+ my $tablename = $mib->{label};
+ my $entry = $mib->{children};
+ my $columns = $entry->[0]{children};
+ foreach my $col (sort { $a->{'subID'} <=> $b->{'subID'} } @$columns) {
+ # store by numeric key so we can sort them later
+ push @{$tables{$tablename}{'column'}}, $col->{'label'};
}
- else {
- $newdepth = max(loadMib($i, $depth), $newdepth);
+ foreach my $index (@{$entry->[0]{'indexes'}}) {
+ my $node = $SNMP::MIB{$index} ||
+ die "can't find info about index $index in table $tablename\n";
+ push @{$tables{$tablename}{'index'}}, $index;
+ }
+ } else {
+ my $children = $mib->{children};
+ my $i;
+ for($i = 0; $i <= $#$children; $i++) {
+ setup_data($children->[$i]);
}
}
- return $newdepth;
+}
+
+sub min {
+ return $_[0] if ($_[0] < $_[1]);
+ return $_[1];
}
sub max {
- my $x = shift;
- my $y = shift;
- return ($x > $y) ? $x : $y;
-}
-
-
-sub read_config() {
- my $configfile = shift;
- my ($type, $lasttoken);
- my $fh = new FileHandle;
- $configfile = "/usr/local/share/snmp/" . $configfile if (!(-f $configfile));
- if ( $fh->open("<$configfile") ) {
- while(<$fh>) {
- next if (/^\s*\#/ || /^\s*$/);
- if (/^\s*type:\s*(.*)/) {
- if (defined($type) && defined($lasttoken) &&
- defined ($variables{$type}{$lasttoken})) {
- chomp($variables{$type}{$lasttoken});
- }
- $type = $1;
- chomp($type);
- } elsif (/include:\s*(.*)/) {
- read_config($1);
- } elsif (/process:\s*(.*)/) {
- push (@process, $1);
- } elsif (/processtable:\s*(.*)/) {
- push (@processtable, $1);
- } elsif (/delete:\s*(.*)/) {
- delete($variables{$type}{$1});
- } elsif (/copy:\s*(.*)/) {
- my $item;
- my $arg = $1;
- chomp($arg);
- foreach $item (keys(%{$variables{$arg}})) {
- $variables{$type}{$item} = $variables{$arg}{$item};
- }
- } else {
- if (/\s*([^:]*):(\s*.*)/) {
- if (!defined($variables{$type}{$1})) {
- if (defined($type) && defined($lasttoken) &&
- defined ($variables{$type}{$lasttoken})) {
- chomp($variables{$type}{$lasttoken});
- }
- $variables{$type}{$1} = $2;
- $lasttoken = $1;
- $variables{$type}{$1} =~ s/^\t+//;
- } else {
- # duplicate entry: tack it on.
- my ($x, $y) = ($1, $2);
- $y =~ s/^\t+//;
- $variables{$type}{$x} .= "\n" . $y;
- }
- } else {
- # continuation line, it started with spaces or a +
- s/^\s*//;
- s/^\+//;
- $variables{$type}{$lasttoken} .= "\n" . $_;
- chomp($variables{$type}{$lasttoken});
- }
- }
- }
- $fh->close();
- } else {
- warn "Config file ($configfile) not found.\n";
- }
-}
-
-sub evalstr {
- my $str = shift;
-# if ($str !~ /^\"/) {
- $str = "\"$str\""; # surround by quotes.
-# }
- eval ($str); # should return a string, with variables expanded
-}
-
-sub evalrstr {
- my $rstr = shift;
-# if ($str !~ /^\"/) {
-# $$rstr = "\"" . $$rstr . "\""; # surround by quotes.
-# }
- eval ("\"$$rstr\""); # should return a string, with variables expanded
+ return $_[0] if ($_[0] > $_[1]);
+ return $_[1];
}
diff --git a/local/mib2c.array-auto.conf b/local/mib2c.array-auto.conf
new file mode 100644
index 0000000..a05fad4
--- /dev/null
+++ b/local/mib2c.array-auto.conf
@@ -0,0 +1,146 @@
+## -*- c -*-
+######################################################################
+## Do the .h file
+######################################################################
+@open include/${name}.h@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * $Id$
+ */
+#ifndef $name.uc_H
+#define $name.uc_H
+
+/** function declarations */
+void init_$name(void);
+@foreach $i table@
+
+#include "${i}_user.h"
+
+void initialize_table_$i(void);
+NodeHandler ${i}_handler;
+@end@
+@foreach $i table@
+
+/* column number definitions for table $i */
+@foreach $c column@
+#define COLUMN_$c.uc $c.subid
+@end@
+@end@
+
+#endif /** $name.uc_H */
+######################################################################
+## Do the .c file
+######################################################################
+@open auto/${name}.c@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * $Id$
+ */
+
+#ifdef IN_UCD_SNMP_SOURCE
+/** If we're compiling this file inside the ucd-snmp source tree */
+
+/** This should always be included first before anything else */
+#include <config.h>
+
+/** minimal include directives */
+#include "mibincl.h"
+#include "util_funcs.h"
+
+#else /** !IN_UCD_SNMP_SOURCE */
+
+#include <ucd-snmp/ucd-snmp-config.h>
+#include <ucd-snmp/ucd-snmp-includes.h>
+#include <ucd-snmp/ucd-snmp-agent-includes.h>
+
+#endif /** !IN_UCD_SNMP_SOURCE */
+
+#include "${name}.h"
+
+
+@foreach $i table@
+/* Initialize the $i table by defining it's contents and how it's structured */
+void
+initialize_table_$i(void)
+{
+ static table_array_callbacks cb;
+ static oid ${i}_oid[] = {$i.commaoid};
+ size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
+ table_registration_info *table_info;
+ handler_registration *my_handler;
+
+ /** create the table structure itself */
+ table_info = SNMP_MALLOC_TYPEDEF(table_registration_info);
+
+ /* if your table is read only, it's easiest to change the
+ HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
+ my_handler = create_handler_registration("$i",
+ table_array_helper_handler,
+ ${i}_oid,
+ ${i}_oid_len,
+ HANDLER_CAN_RWRITE);
+
+ if (!my_handler || !table_info) {
+ snmp_log(LOG_ERR, "malloc failed in "
+ "initialize_table_${i}_handler\n");
+ return; /** mallocs failed */
+ }
+
+ /***************************************************
+ * Setting up the table's definition
+ */
+ @foreach $idx index@
+ /** index: $idx */
+ table_helper_add_index(table_info, $idx.type);
+ @end@
+
+ @eval $minv = 0xffffffff@
+ @eval $maxv = 0@
+ @foreach $c column@
+ @if ! $c.noaccess@
+ @eval $minv = min($minv, $c.subid)@
+ @end@
+ @eval $maxv = max($maxv, $c.subid)@
+ @end@
+ table_info->min_column = $minv;
+ table_info->max_column = $maxv;
+
+ /***************************************************
+ * registering the table with the master agent
+ */
+ cb.get_value = ${i}_get_value;
+
+#ifdef ${i}_SET_HANDLING
+#ifdef ${i}_ROW_CREATION
+ cb.create_row = ${i}_create_row;
+ cb.delete_row = ${i}_delete_row;
+#else
+ cb.create_row = cb.delete_row= NULL;
+#endif
+ cb.set_reserve1 = ${i}_set_reserve1;
+ cb.set_reserve2 = ${i}_set_reserve2;
+ cb.set_action = ${i}_set_action;
+ cb.set_commit = ${i}_set_commit;
+ cb.set_free = ${i}_set_free;
+ cb.set_undo = ${i}_set_undo;
+#else
+ cb.set_reserve1 = cb.set_reserve2 = cb.set_action = cb.set_commit =
+ cb.set_free = cb.set_undo = NULL;
+#endif
+ DEBUGMSGTL(("initialize_table_$i",
+ "Registering table $i "
+ "as a table array\n"));
+ register_table_array(my_handler, table_info, &cb, 1);
+}
+@end@
+
+/** Initialzies the $name module */
+void
+init_$name(void)
+{
+ /** here we initialize all the tables we're planning on supporting */
+ @foreach $i table@
+ initialize_table_$i();
+ @end@
+}
+@end@
diff --git a/local/mib2c.array-user.conf b/local/mib2c.array-user.conf
new file mode 100644
index 0000000..5642fe7
--- /dev/null
+++ b/local/mib2c.array-user.conf
@@ -0,0 +1,1249 @@
+## -*- c -*-
+######################################################################
+## Do the .h file
+## @perleval $vars{shortname} =~ s/([A-Z])[a-z]+/$1/g@
+######################################################################
+@foreach $i table@
+@open ${i}.h@
+@eval $hack = "Id"
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * $Id$
+ *
+ * $$hack:$
+ *
+ * Yes, there is lots of code here that you might not use. But it is much
+ * easier to remove code than to add it!
+ */
+#ifndef $i.uc_H
+#define $i.uc_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <net-snmp/oid_array.h>
+#include <net-snmp/table_array.h>
+
+ /**
+ * un-comment this line if this table has any external indexes.
+ * This warning, and the rest, may be deleted once you've written
+ * the appropriate sections of code.
+ */
+ /** #define ${i}_EXTERNAL_INDEX */
+
+typedef struct ${i}_context_s {
+ oid_array_header index; /** THIS MUST BE FIRST!!! */
+
+ /*************************************************************
+ * You can store data internally in this structure.
+ *
+ * TODO: You'll probably have to fix a few types here...
+ */
+#ifdef ${i}_EXTERNAL_INDEX
+#warning "TODO: add code for external index!"
+#endif
+ @foreach $c column@
+ /** $c.syntax = $c.type */
+ @eval $have_type = 0@
+ @if "$c.type" eq "ASN_OCTET_STR"@
+ @eval $have_type = 1@
+ @eval $o_len = "65535"@
+ @if "$c.syntax" eq "DisplayString"@
+ @eval $o_len = "255"@
+ @end@
+ @if "$c.syntax" eq "SnmpAdminString"@
+ @eval $o_len = "255"@
+ @end@
+ char $c[$o_len];
+ long ${c}_len;
+ @end@
+ @if "$c.type" eq "ASN_OBJECT_ID"@
+ @eval $have_type = 1@
+ oid $c[MAX_OID_LEN];
+ long ${c}_len;
+ @end@
+ @if "$c.type" eq "ASN_UNSIGNED"@
+ @eval $have_type = 1@
+ unsigned long $c;
+ @end@
+ @if "$c.type" eq "ASN_TIMETICKS"@
+ @eval $have_type = 1@
+ unsigned long $c;
+ @end@
+ @if "$c.type" eq "ASN_IPADDRESS"@
+ @eval $have_type = 1@
+ unsigned long $c;
+ @end@
+ @if "$c.type" eq "ASN_UINTEGER"@
+ @eval $have_type = 1@
+ unsigned long $c;
+ @end@
+ @if "$c.type" eq "ASN_COUNTER"@
+ @eval $have_type = 1@
+ unsigned long $c;
+ @end@
+ @if $have_type == 0@
+ long $c;
+ @end@
+
+ @end@
+
+ /*
+ * OR
+ *
+ * Keep a pointer to your data
+ */
+ void * data;
+
+ /*
+ *add anything else you want here
+ */
+
+} ${i}_context;
+
+/*************************************************************
+ * function declarations
+ */
+void init_$i(void);
+void initialize_table_$i(void);
+const ${i}_context * ${i}_get_by_idx(oid_array_header *);
+int ${i}_get_value(request_info *, oid_array_header *, table_request_info *);
+
+
+/*************************************************************
+ * oid declarations
+ */
+extern oid ${i}_oid[];
+extern size_t ${i}_oid_len;
+
+/*************************************************************
+ * column number definitions for table $i
+ */
+@foreach $c column@
+#define COLUMN_$c.uc $c.subid
+@if "$c.syntax" eq "RowStatus"@
+ @eval $rs_name = "$c"@
+@end@
+@if "$c.syntax" eq "StorageType"@
+ @eval $st_name = "$c"@
+@end@
+@end@
+
+/* comment out the following line if you dont handle SET-REQUEST for $i */
+#define ${i}_SET_HANDLING
+
+/* comment out the following line if you cant create new rows */
+#define ${i}_ROW_CREATION
+
+/* comment out the following line if you dont want the secondary
+ * index binary tree. */
+#define ${i}_TREE
+
+@if "$rs_name" ne ""@
+/* uncommend the following line if you allow modifications to an
+ * active row */
+/** define ${i}_CAN_MODIFY_ACTIVE_ROW */
+
+@end@
+#ifdef ${i}_SET_HANDLING
+void ${i}_set_reserve1( array_group * );
+void ${i}_set_reserve2( array_group * );
+void ${i}_set_action( array_group * );
+void ${i}_set_commit( array_group * );
+void ${i}_set_free( array_group * );
+void ${i}_set_undo( array_group * );
+#endif
+
+#ifdef ${i}_ROW_CREATION
+oid_array_header * ${i}_create_row( oid_array_header* );
+oid_array_header * ${i}_duplicate_row( oid_array_header* );
+oid_array_header * ${i}_delete_row( oid_array_header* );
+#endif
+
+#ifdef ${i}_TREE
+${i}_context * ${i}_get( const char *name, int len );
+#endif
+
+/**
+ And just for your enjoyment:
+
+ @foreach $c column@
+name : $c
+uppercase : $c.uc
+dotted full OID : $c.objectID
+comma separated OID : $c.commaoid
+last component of oid: $c.subid
+length of the oid : $c.oidlength
+node's ASN_XXX type : $c.type
+1 if it's writable : $c.settable
+node's access type : $c.access
+node's status : $c.status
+node's syntax : $c.syntax
+
+ @end@
+*/
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /** $name.uc_H */
+@end@
+######################################################################
+## Do the .c file
+######################################################################
+@foreach $i table@
+@open ${name}.c@
+@eval $hack = "Id"@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * $Id$
+ *
+ * $$hack:$
+ *
+ *
+ * For help understanding NET-SNMP in general, please check the
+ * documentation and FAQ at:
+ *
+ * http://www.net-snmp.org/
+ *
+ *
+ * For help understanding this code, the agent and how it processes
+ * requests, please check the following references.
+ *
+ * http://www.net-snmp.org/tutorial/
+ * http://www.net-snmp.org/tutorial/toolkit/
+ * http://www.net-snmp.org/tutorial/agent/
+ *
+ *
+ * And if all else fails, send a detailed message to the developers
+ * describing the problem you are having to:
+ *
+ * net-snmp-coders@lists.sourceforge.net
+ *
+ * Yes, there is lots of code here that you might not use. But it is much
+ * easier to remove code than to add it!
+ */
+#ifdef IN_UCD_SNMP_SOURCE
+/** If we're compiling this file inside the ucd-snmp source tree */
+
+/** This should always be included first before anything else */
+#include <config.h>
+
+/** minimal include directives */
+#include "mibincl.h"
+#include "util_funcs.h"
+#include "table.h"
+
+#else /** !IN_UCD_SNMP_SOURCE */
+
+#include <ucd-snmp/ucd-snmp-config.h>
+#include <ucd-snmp/ucd-snmp-includes.h>
+#include <ucd-snmp/ucd-snmp-agent-includes.h>
+
+#endif /** !IN_UCD_SNMP_SOURCE */
+
+#include <assert.h>
+
+#include "${i}.h"
+
+static handler_registration *my_handler = NULL;
+
+oid ${i}_oid[] = {$i.commaoid};
+size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
+
+
+#ifdef ${i}_TREE
+/************************************************************
+ * keep binary tree to find context by name
+ */
+static int ${i}_cmp( void *lhs, void *rhs );
+static ${i}_context * ${i}_find( ${i}_context *item );
+static ${i}_context * ${i}_insert( ${i}_context *item );
+static ${i}_context * ${i}_delete( ${i}_context * item );
+static void * tree = NULL;
+
+/************************************************************
+ * compare two context pointers here. Return -1 if lhs < rhs,
+ * 0 if lhs == rhs, and 1 if lhs > rhs.
+ */
+static int
+${i}_cmp( void *lhs, void *rhs )
+{
+ ${i}_context *context_l =
+ (${i}_context *)lhs;
+ ${i}_context *context_r =
+ (${i}_context *)rhs;
+
+ /*
+ * check primary key, then secondary. Add your own code if
+ * there are more than 2 indexes
+ */
+ int rc;
+ rc = strncmp( context_l->xxName, context_r->xxName,
+ SNMP_MIN(context_l->xxName_len, context_r->xxName_len) );
+
+ if(rc)
+ return rc;
+
+ /*
+ * secondary keys
+ */
+ if(context_l->yy < context_r->yy)
+ return -1;
+
+ return (context_l->yy == context_r->yy) ? 0 : 1;
+}
+
+/************************************************************
+ * search tree
+ */
+${i}_context *
+${i}_get( const char *name, int len )
+{
+ /** XXX TODO: handle null termination */
+ ${i}_context tmp;
+ if(len > sizeof(tmp.xxName))
+ return NULL;
+
+ strncpy( tmp.xxName, name, sizeof(tmp.xxName) );
+ tmp.xxName_len = len;
+
+ return ${i}_find( &tmp );
+}
+#endif
+
+
+/************************************************************
+/* Initialzies the $name module
+ */
+void
+init_$name(void)
+{
+ initialize_table_$i();
+
+ /*
+ * TODO: perform and startup stuff here
+ */
+}
+
+#ifdef ${i}_SET_HANDLING
+
+/*
+ * the *_extract_index routine
+ */
+int
+${i}_extract_index( ${i}_context * ctx, oid_array_header * hdr )
+{
+ /*
+ * temporary local storage for extracting oid index
+ */
+ @eval $first_idx = ""@
+ @foreach $idx index@
+ @if "$first_idx" eq ""@
+ @eval $first_idx = $idx@
+ @end@
+ struct variable_list var_$idx;
+ @end@
+ int err = 0;
+
+ /*
+ * copy index, if provided
+ */
+ if(hdr) {
+ assert(ctx->index.idx == NULL);
+ if(snmp_clone_mem( (void*)&ctx->index.idx, hdr->idx,
+ hdr->idx_len * sizeof(oid) )) {
+ return -1;
+ }
+ ctx->index.idx_len = hdr->idx_len;
+ }
+
+ /**
+ * Create variable to hold each component of the index
+ */
+#ifdef ${i}_EXTERNAL_INDEX
+#warning "TODO: add code for external index!"
+#endif
+ @foreach $idx index@
+ memset( &var_$idx, 0x00, sizeof(var_$idx) );
+ var_${idx}.type = $idx.type;
+ var_$idx.next_variable = &var_XX;
+
+ @end@
+
+ /*
+ * parse the oid into the individual components
+ */
+ parse_oid_indexes( hdr->idx, hdr->idx_len, &var_$first_idx );
+
+ /*
+ * copy components into the context structure
+ */
+#ifdef ${i}_EXTERNAL_INDEX
+#warning "TODO: add code for external index!"
+#endif
+ @foreach $idx index@
+ @eval $have_type = 0@
+ @if "$idx.type" eq "ASN_OCTET_STR"@
+ @eval $have_type = 1@
+ if(var_$idx.val_len > sizeof(ctx->$idx))
+ err = -1;
+ else
+ memcpy( ctx->$idx, var_$idx.val.string, var_$idx.val_len );
+ ctx->${idx}_len = var_$idx.val_len;
+ @end@
+ @if "$idx.type" eq "ASN_OBJECT_ID"@
+ @eval $have_type = 1@
+ memcpy( ctx->$idx, var_$idx.val.string, var_$idx.val_len );
+ ctx->$idx_len = var_$idx.val_len;
+ @end@
+ @if $have_type == 0@
+ ctx->$idx = *var_$idx.val.integer;
+ @end@
+
+ @end@
+
+ /*
+ * TODO: check any syntax requrements for indexes here
+ */
+
+
+ /*
+ * parsing may have allocated memory. free it.
+ */
+ snmp_reset_var_buffers( &var_$first_idx );
+
+ return err;
+}
+
+@if "$rs_name" ne ""@
+/************************************************************
+ * the *_can_activate routine is called routine is called
+ * when a row is changed to determine if all the values
+ * set are consistent with the row's rules for a row status
+ * of ACTIVE.
+ *
+ * return 1 if the row could be ACTIVE
+ * return 0 if the row is not ready for the ACTIVE state
+ */
+int ${i}_can_activate(${i}_context *ctx_old,
+ ${i}_context *ctx_new,
+ array_group * ag)
+{
+ /*
+ * TODO: check for activation requirements here
+ */
+ return 1;
+}
+
+/************************************************************
+ * the *_can_deactivate routine is called when a row that is
+ * currently ACTIVE is set to a state other than ACTIVE. If
+ * there are conditions in which a row should not be allowed
+ * to transition out of the ACTIVE state (such as the row being
+ * referred to by another row or table), check for them here.
+ *
+ * return 1 if the row can set to a non-ACTIVE state
+ * return 0 if the row must remain in the ACTIVE state
+ */
+int ${i}_can_deactivate(${i}_context *ctx_old,
+ ${i}_context *ctx_new,
+ array_group * ag)
+{
+ /*
+ * TODO: check for deactivation requirements here
+ */
+ return 1;
+}
+
+@end@
+/************************************************************
+ * the *_can_delete routine is call to determine if a row
+ * can be deleted.
+ *
+ * return 1 if the row can be deleted
+ * return 0 if the row cannot be deleted
+ */
+int ${i}_can_delete(${i}_context *ctx_old,
+ ${i}_context *ctx_new,
+ array_group * ag)
+{
+ /*
+ * probably shouldn't delete a row that we can't
+ * deactivate.
+ */
+ if(${i}_can_deactivate(ctx_old,ctx_new,ag))
+ return 1;
+
+ /*
+ * TODO: check for other deletion requirements here
+ */
+ return 0;
+}
+
+#ifdef ${i}_ROW_CREATION
+/************************************************************
+ * the *_create_row routine is called by the table handler
+ * to create a new row for a given index. If you need more
+ * information (such as column values) to make a decision
+ * on creating rows, you must create an initial row here
+ * (to hold the column values), and you can examine the
+ * situation in more detail in the *_set_reserve1 or later
+ * states of set processing. Simple check for a NULL ctx_old
+ * in those states and do detailed creation checking there.
+ *
+ * returns a newly allocated ${i}_context
+ * structure if the specified indexes are not illegal
+ * returns NULL for errors or illegal index values.
+ */
+oid_array_header * ${i}_create_row( oid_array_header* hdr)
+{
+ ${i}_context * ctx =
+ (${i}_context*)calloc(1,sizeof(*ctx));
+ if(!ctx)
+ return NULL;
+
+ /*
+ * TODO: check indexes, if necessary.
+ */
+ if(${i}_extract_index( ctx, hdr )) {
+ free(ctx->index.idx);
+ free(ctx);
+ return NULL;
+ }
+
+ /*
+ * TODO: initialize any default values here. This is also
+ * first place you really should allocate any memory for
+ * yourself to use. If you allocated memory earlier,
+ * make sure you free it for earlier error cases!
+ */
+ /**
+ @foreach $c column@
+ @if $c.settable@
+ ctx->$c = 0;
+ @end@
+ @end@
+ */
+
+ return (oid_array_header *)ctx;
+}
+
+/************************************************************
+ * the *_duplicate row routine
+ */
+oid_array_header * ${i}_duplicate_row( oid_array_header* hdr)
+{
+ ${i}_context * ctx_old = (${i}_context *)hdr;
+ ${i}_context * ctx_new;
+ if(!ctx_old)
+ return;
+
+ ctx_new = (${i}_context*)calloc(1,sizeof(*ctx_new));
+ if(!ctx_new)
+ return NULL;
+
+ /*
+ * copy index, if provided
+ */
+ assert(ctx_old->index.idx != NULL);
+ if(snmp_clone_mem( (void*)&ctx_new->index.idx, ctx_old->index.idx,
+ ctx_old->index.idx_len * sizeof(oid) )) {
+ free(ctx_new);
+ ctx_new = NULL;
+ return NULL;
+ }
+ ctx_new->index.idx_len = ctx_old->index.idx_len;
+
+
+ /*
+ * copy components into the context structure
+ */
+#ifdef ${i}_EXTERNAL_INDEX
+#warning "TODO: add code for external index!"
+#endif
+ @foreach $c column@
+ @eval $have_type = 0@
+ @if "$c.type" eq "ASN_OCTET_STR"@
+ @eval $have_type = 1@
+ memcpy( ctx_new->$c, ctx_old->$c, ctx_old->${c}_len );
+ ctx_new->${c}_len = ctx_old->${c}_len;
+ @end@
+ @if "$c.type" eq "ASN_OBJECT_ID"@
+ @eval $have_type = 1@
+ memcpy( ctx_old->$c, ctx_new->$c, ctx_old->${c}_len );
+ ctx_new->${c}_len = ctx_old->${c}_len;
+ @end@
+ @if $have_type == 0@
+ ctx_new->$c = ctx_old->$c;
+ @end@
+
+ @end@
+ return (oid_array_header*) ctx_new;
+}
+
+/************************************************************
+ * the *_delete_row method is called to delete a row.
+ */
+oid_array_header * ${i}_delete_row( oid_array_header* hdr)
+{
+ ${i}_context * ctx =
+ (${i}_context*)hdr;
+
+ if(ctx->index.idx)
+ free(ctx->index.idx);
+
+ /*
+ * TODO: release any memory you allocated here...
+ */
+
+ /*
+ * release header
+ */
+ free( ctx );
+
+ return NULL;
+}
+#endif
+
+
+/************************************************************
+ * RESERVE is used to check the syntax of all the variables
+ * provided, that the values being set are sensible and consistent,
+ * and to allocate any resources required for performing the SET.
+ * After this stage, the expectation is that the set ought to
+ * succeed, though this is not guaranteed. (In fact, with the UCD
+ * agent, this is done in two passes - RESERVE1, and
+ * RESERVE2, to allow for dependancies between variables).
+ *
+ * AFTER calling this routine, the agent will call duplicate_row
+ * to create a copy of the row.
+ *
+ * next state -> SET_RESERVE2 || SET_FREE
+ */
+void ${i}_set_reserve1( array_group *ag )
+{
+ ${i}_context *ctx_new =
+ (${i}_context *)ag->new_row;
+ ${i}_context *ctx_old =
+ (${i}_context *)ag->old_row;
+ struct variable_list *var;
+ array_group_item *current;
+
+ /*
+ * TODO: loop through columns, check syntax and lengths. For
+ * columns which have no dependencies, you could also move
+ * the value/range checking here to attempt to catch error
+ * cases as early as possible.
+ */
+ for( current = ag->list; current; current = current->next ) {
+
+ var = current->ri->requestvb;
+
+ switch(current->tri->colnum) {
+
+ @foreach $c column@
+ @if $c.settable@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ if( var->type != $c.type ) {
+ set_mode_request_error(MODE_SET_BEGIN, current->ri,
+ SNMP_ERR_WRONGTYPE );
+ }
+ @if "$c.type" eq "ASN_OCTET_STR"@
+ else if( var->val_len > sizeof(ctx_new->$c) ) {
+ @end@
+ @if "$c.type" eq "ASN_OBJECT_ID"@
+ else if( var->val_len > sizeof(ctx_new->$c) ) {
+ @end@
+ @if "$c.type" ne "ASN_OCTET_STR"@
+ else if( var->val_len != sizeof(ctx_new->$c) ) {
+ @end@
+ set_mode_request_error(MODE_SET_BEGIN, current->ri,
+ SNMP_ERR_WRONGLENGTH );
+ }
+ break;
+
+ @end@
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_set_reserve1\n");
+ }
+
+ ag->status = SNMP_MAX( ag->status, current->ri->status );
+ }
+
+ /*
+ * done with all the columns. Could check row related
+ * requirements here.
+ */
+}
+
+void ${i}_set_reserve2( array_group *ag )
+{
+ struct variable_list *var;
+ ${i}_context *ctx_new = (${i}_context *)ag->new_row;
+ ${i}_context *ctx_old = (${i}_context *)ag->old_row;
+ array_group_item *current;
+
+ @if "$st_name" ne ""@
+ STORAGETYPE_DECLARE;
+ @end@
+ @if "$rs_name" ne ""@
+ ROWSTATUS_DECLARE;
+
+ @end@
+ /*
+ * TODO: loop through columns, check for valid
+ * values and any range constraints.
+ */
+ for( current = ag->list; current; current = current->next ) {
+
+ var = current->ri->requestvb;
+
+ switch(current->tri->colnum) {
+
+ @foreach $c column@
+ @if $c.settable@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ @eval $have_check = 0@
+ @if "$c" eq "$st_name"@
+ @eval $have_check = 1@
+ STORAGETYPE_VALIDATE( var, current->ri );
+ @end@
+ @if "$c" eq "$rs_name"@
+ @eval $have_check = 1@
+ ROWSTATUS_VALIDATE( var, current->ri );
+ @end@
+ @if $have_check == 0@
+ @if "$c.type" eq "ASN_IPADDRESS"@
+ @eval $have_check = 1@
+ if ( XXX_check_ip( *var->val.integer ) ) {
+ @end@
+ @if "$c.type" eq "ASN_OBJECT_ID"@
+ @eval $have_check = 1@
+ if ( XXX_check_oid( var ) ) {
+ @end@
+ @if "$c.type" eq "ASN_OCTET_STR"@
+ @eval $have_check = 1@
+ if ( XXX_check_value( var->val.string, XXX ) ) {
+ @end@
+ @if "$c.syntax" eq "TruthValue"@
+ @eval $have_check = 1@
+ /** TruthValue allowable values */
+ if ((*var->val.integer != 2) &&
+ (*var->val.integer != 1)) {
+ @end@
+ @if $have_check != 1@
+ if ( *var->val.integer != XXX ) {
+ @end@
+ /** or SNMP_ERR_INCONSISTENTVALUE */
+ set_mode_request_error(MODE_SET_BEGIN, current->ri,
+ SNMP_ERR_BADVALUE );
+ }
+ @end@
+ break;
+
+ @end@
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_set_reserve2\n");
+ }
+ }
+
+ /*
+ * done with all the columns. Could check row related
+ * requirements here.
+ */
+ @if "$st_name" ne ""@
+ STORAGETYPE_CHECK( ctx_new->$st_name );
+ @end@
+ @if "$rs_name" ne ""@
+ ROWSTATUS_CHECK( ctx_new->$rs_name, ctx_new->$st_name, ag->list->ri );
+ @end@
+}
+
+/************************************************************
+ * Assuming that the RESERVE phase was successful, the next
+ * stage is indicated by the action value ACTION. This is used
+ * to actually implement the set operation. However, this must
+ * either be done into temporary (persistent) storage, or the
+ * previous value stored similarly, in case any of the subsequent
+ * ACTION calls fail.
+ *
+ * BEFORE calling this routine the agent will replace the old_row
+ * in the array with the new_row.
+ */
+void ${i}_set_action( array_group *ag )
+{
+ struct variable_list *var;
+ ${i}_context *ctx_new = (${i}_context *)ag->new_row;
+ ${i}_context *ctx_old = (${i}_context *)ag->old_row;
+ array_group_item *current;
+
+ @if "$rs_name" ne ""@
+ request_info * row_status_vb = NULL;
+ int row_err = 0;
+ @end@
+
+ assert( ctx_old || ctx_new );
+
+ /*
+ * TODO: loop through columns, copy varbind values
+ * to context structure for the row.
+ */
+ for( current = ag->list; current; current = current->next ) {
+
+ var = current->ri->requestvb;
+
+ switch(current->tri->colnum) {
+
+ @foreach $c column@
+ @if $c.settable@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ @eval $have_type = 0@
+ @if "$c.type" eq "ASN_OCTET_STR"@
+ @eval $have_type = 1@
+ memcpy(ctx_new->$c,var->val.string,var->val_len);
+ ctx_new->${c}_len = var->val_len;
+ @end@
+ @if "$c.type" eq "ASN_OBJECT_ID"@
+ @eval $have_type = 1@
+ memcpy(ctx_new->$c,var->val.objid,var->val_len);
+ ctx_new->${c}_len = var->val_len;
+ @end@
+ @if "$rs_name" eq "$c"@
+ row_status_vb = current->ri;
+ @end@
+ @if $have_type == 0@
+ ctx_new->$c = *var->val.integer;
+ @end@
+ break;
+
+ @end@
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_set_action\n");
+ }
+ }
+
+ /*
+ * done with all the columns. Could check row related
+ * requirements here.
+ */
+ @if "$rs_name" ne ""@
+ if(!row_status_vb)
+ row_status_vb = ag->list->ri;
+#ifndef ${i}_CAN_MODIFY_ACTIVE_ROW
+ if( ctx_old && RS_IS_ACTIVE(ctx_old->$rs_name) &&
+ ctx_new && RS_IS_ACTIVE(ctx_new->$rs_name) ) {
+ row_err = 1;
+ }
+#endif
+
+ /*
+ * check activation/deactivation
+ */
+ if( ctx_new ) {
+ /*
+ * is this row ready to be active?
+ */
+ int row_ready = ${i}_can_activate(ctx_old,ctx_new,ag);
+
+ /*
+ * either a new row, or change to old row
+ */
+ if( RS_IS_GOING_ACTIVE(ctx_new->$rs_name) ) {
+ if( ! row_ready ) {
+ row_err = 1;
+ }
+ ctx_new->$rs_name = RS_ACTIVE;
+ }
+ else {
+ if(ctx_old) {
+ /*
+ * change
+ */
+ if( RS_IS_ACTIVE(ctx_old->$rs_name) ) {
+ /*
+ * check preqs for deactivation
+ */
+ if(! ${i}_can_deactivate(ctx_old,ctx_new,ag)) {
+ row_err = 1;
+ }
+ }
+ }
+ else {
+ /*
+ * new row
+ */
+ }
+
+ if( row_ready )
+ ctx_new->$rs_name = RS_NOTINSERVICE;
+ else
+ ctx_new->$rs_name = RS_NOTREADY;
+ }
+ }
+ else {
+ /*
+ * check pre-reqs for delete row
+ */
+ if(! ${i}_can_delete(ctx_old,ctx_new,ag)) {
+ row_err = 1;
+ }
+ }
+ if(row_err) {
+ set_mode_request_error(MODE_SET_BEGIN, row_status_vb,
+ SNMP_ERR_INCONSISTENTVALUE);
+ return;
+ }
+
+ @end@
+ /*
+ * TODO: if you have dependencies on other tables, this would be
+ * a good place to check those, too.
+ */
+
+#ifdef ${i}_TREE
+ /*
+ * update secondary index
+ */
+ if(ctx_old)
+ ${i}_delete( ctx_old );
+ if(ctx_new)
+ ${i}_insert( ctx_new );
+#endif
+}
+
+/************************************************************
+ * Only once the ACTION phase has completed successfully, can
+ * the final COMMIT phase be run. This is used to complete any
+ * writes that were done into temporary storage, and then release
+ * any allocated resources. Note that all the code in this phase
+ * should be "safe" code that cannot possibly fail (cue
+ * hysterical laughter). The whole intent of the ACTION/COMMIT
+ * division is that all of the fallible code should be done in
+ * the ACTION phase, so that it can be backed out if necessary.
+ */
+void ${i}_set_commit( array_group *ag )
+{
+ struct variable_list *var;
+ ${i}_context *ctx_new = (${i}_context *)ag->new_row;
+ ${i}_context *ctx_old = (${i}_context *)ag->old_row;
+ array_group_item *current;
+
+ /*
+ * loop through columns
+ */
+ for( current = ag->list; current; current = current->next ) {
+
+ var = current->ri->requestvb;
+
+ switch(current->tri->colnum) {
+
+ @foreach $c column@
+ @if $c.settable@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ break;
+
+ @end@
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_set_commit\n");
+ }
+ }
+
+ /*
+ * done with all the columns. Could check row related
+ * requirements here.
+ */
+}
+
+/************************************************************
+ * If either of the RESERVE calls fail, the write routines
+ * are called again with the FREE action, to release any resources
+ * that have been allocated. The agent will then return a failure
+ * response to the requesting application.
+ *
+ * AFTER calling this routine, the agent will delete old_row.
+ */
+void ${i}_set_free( array_group *ag )
+{
+ struct variable_list *var;
+ ${i}_context *ctx_new = (${i}_context *)ag->new_row;
+ ${i}_context *ctx_old = (${i}_context *)ag->old_row;
+ array_group_item *current;
+
+ /*
+ * loop through columns
+ */
+ for( current = ag->list; current; current = current->next ) {
+
+ var = current->ri->requestvb;
+
+ switch(current->tri->colnum) {
+
+ @foreach $c column@
+ @if $c.settable@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ break;
+
+ @end@
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_set_free\n");
+ }
+ }
+
+ /*
+ * done with all the columns. Could check row related
+ * requirements here.
+ */
+}
+
+/************************************************************
+ * If the ACTION phase does fail (for example due to an apparently
+ * valid, but unacceptable value, or an unforeseen problem), then
+ * the list of write routines are called again, with the UNDO
+ * action. This requires the routine to reset the value that was
+ * changed to its previous value (assuming it was actually changed),
+ * and then to release any resources that had been allocated. As
+ * with the FREE phase, the agent will then return an indication
+ * of the error to the requesting application.
+ *
+ * BEFORE calling this routine, the agent will remove the new row
+ * from the table and replace it with the old row.
+ *
+ * AFTER calling this routing, the agent will delete the new_row.
+ */
+void ${i}_set_undo( array_group *ag )
+{
+ struct variable_list *var;
+ ${i}_context *ctx_new = (${i}_context *)ag->new_row;
+ ${i}_context *ctx_old = (${i}_context *)ag->old_row;
+ array_group_item *current;
+
+ /*
+ * loop through columns
+ */
+ for( current = ag->list; current; current = current->next ) {
+
+ var = current->ri->requestvb;
+
+ switch(current->tri->colnum) {
+
+ @foreach $c column@
+ @if $c.settable@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ break;
+
+ @end@
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_set_undo\n");
+ }
+ }
+
+ /*
+ * done with all the columns. Could check row related
+ * requirements here.
+ */
+#ifdef ${i}_TREE
+ /*
+ * update secondary index
+ */
+ if(ctx_new)
+ ${i}_delete( ctx_new );
+ if(ctx_old)
+ ${i}_insert( ctx_old );
+#endif
+}
+
+#endif /** ${i}_SET_HANDLING */
+
+
+#ifdef ${i}_TREE
+static ${i}_context *
+${i}_find( ${i}_context *item )
+{
+ ${i}_context **item_ptr =
+ (${i}_context **)
+ tfind( item, &tree, ${i}_cmp );
+
+ return item_ptr ? *item_ptr : NULL;
+}
+
+static ${i}_context *
+${i}_insert( ${i}_context *item )
+{
+ ${i}_context **item_ptr =
+ (${i}_context **)
+ tsearch( item, &tree, ${i}_cmp );
+
+ return item_ptr ? *item_ptr : NULL;
+}
+
+static ${i}_context *
+${i}_delete( ${i}_context *item )
+{
+ ${i}_context **item_ptr =
+ (${i}_context **)
+ tdelete( item, &tree, ${i}_cmp );
+
+ return item_ptr ? *item_ptr : NULL;
+}
+
+#endif
+
+/************************************************************
+ *
+ * Initialize the $i table by defining it's contents and how it's structured
+ */
+void
+initialize_table_$i(void)
+{
+ static table_array_callbacks cb;
+ table_registration_info *table_info;
+
+ if(my_handler) {
+ snmp_log(LOG_ERR, "initialize_table_${i}_handler called again\n");
+ return;
+ }
+
+ memset(&cb, 0x00, sizeof(cb));
+
+ /** create the table structure itself */
+ table_info = SNMP_MALLOC_TYPEDEF(table_registration_info);
+
+ /* if your table is read only, it's easiest to change the
+ HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
+ my_handler = create_handler_registration("$i",
+ table_array_helper_handler,
+ ${i}_oid,
+ ${i}_oid_len,
+ HANDLER_CAN_RWRITE);
+
+ if (!my_handler || !table_info) {
+ snmp_log(LOG_ERR, "malloc failed in "
+ "initialize_table_${i}_handler\n");
+ return; /** mallocs failed */
+ }
+
+ /***************************************************
+ * Setting up the table's definition
+ */
+ /*
+ * TODO: add any external indexes here.
+ */
+#ifdef ${i}_EXTERNAL_INDEX
+#warning "TODO: add code for external index!"
+#endif
+
+ /*
+ * internal indexes
+ */
+ @foreach $idx index@
+ /** index: $idx */
+ table_helper_add_index(table_info, $idx.type);
+ @end@
+
+ @eval $minv = 0xffffffff@
+ @eval $maxv = 0@
+ @foreach $c column@
+ @if ! $c.noaccess@
+ @eval $minv = min($minv, $c.subid)@
+ @end@
+ @eval $maxv = max($maxv, $c.subid)@
+ @end@
+ table_info->min_column = $minv;
+ table_info->max_column = $maxv;
+
+ /***************************************************
+ * registering the table with the master agent
+ */
+ cb.get_value = ${i}_get_value;
+
+#ifdef ${i}_SET_HANDLING
+#ifdef ${i}_ROW_CREATION
+ cb.create_row = ${i}_create_row;
+ cb.duplicate_row = ${i}_duplicate_row;
+ cb.delete_row = ${i}_delete_row;
+#endif
+ cb.set_reserve1 = ${i}_set_reserve1;
+ cb.set_reserve2 = ${i}_set_reserve2;
+ cb.set_action = ${i}_set_action;
+ cb.set_commit = ${i}_set_commit;
+ cb.set_free = ${i}_set_free;
+ cb.set_undo = ${i}_set_undo;
+#endif
+ DEBUGMSGTL(("initialize_table_$i",
+ "Registering table $i "
+ "as a table array\n"));
+ register_table_array(my_handler, table_info, &cb, 1);
+}
+
+/************************************************************
+ * ${i}_get_value
+ */
+int ${i}_get_value(
+ request_info *request,
+ oid_array_header *item,
+ table_request_info *table_info )
+{
+ struct variable_list *var = request->requestvb;
+ ${i}_context *context = (${i}_context *)item;
+
+ switch(table_info->colnum) {
+
+ @foreach $c column@
+ @eval $have_type = 0@
+ case COLUMN_$c.uc:
+ /** $c.syntax = $c.type */
+ snmp_set_var_typed_value(var, $c.type,
+ (char*)&context->$c,
+ @if "$c.type" eq "ASN_OBJECT_ID"@
+ @eval $have_type = 1@
+ context->${c}_len );
+ @end@
+ @if "$c.type" eq "ASN_OCTET_STR"@
+ @eval $have_type = 1@
+ context->${c}_len );
+ @end@
+ @if $have_type == 0@
+ sizeof(context->$c) );
+ @end@
+ break;
+
+ @end@
+ default: /** We shouldn't get here */
+ snmp_log(LOG_ERR, "unknown column in "
+ "${i}_get_value\n");
+ }
+}
+
+const ${i}_context *
+${i}_get_by_idx(oid_array_header * hdr)
+{
+ return (const ${i}_context *)
+ table_array_get_by_index( my_handler, hdr );
+}
+
+@end@
+@end@
+@end@
diff --git a/local/mib2c.create-dataset.conf b/local/mib2c.create-dataset.conf
new file mode 100644
index 0000000..ab08ace
--- /dev/null
+++ b/local/mib2c.create-dataset.conf
@@ -0,0 +1,95 @@
+## -*- c -*-
+######################################################################
+## Do the .h file
+######################################################################
+@open ${name}.h@
+/* Note: this file originally auto-generated by mib2c */
+#ifndef $name.uc_H
+#define $name.uc_H
+
+/* function declarations */
+void init_$name(void);
+@foreach $i table@
+void initialize_table_$i(void);
+NodeHandler ${i}_handler;
+@end@
+@foreach $i table@
+
+/* column number definitions for table $i */
+ @foreach $c column@
+ #define COLUMN_$c.uc $c.subid
+ @end@
+@end@
+#endif /* $name.uc_H */
+######################################################################
+## Do the .c file
+######################################################################
+@open ${name}.c@
+/* Note: this file originally auto-generated by mib2c */
+@foreach $i table@
+/** Initialize the $i table by defining it's contents and how it's structured */
+void
+initialize_table_$i(void)
+{
+ static oid ${i}_oid[] = {$i.commaoid};
+ size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
+ table_data_set *table_set;
+
+ /* create the table structure itself */
+ table_set = create_table_data_set("$i");
+
+ /***************************************************
+ * Adding indexes
+ */
+ @foreach $idx index@
+ /*
+ * declaring the $idx index
+ */
+ DEBUGMSGTL(("initialize_table_$i",
+ "adding index $idx.label of type $idx.type to table $i\n"));
+ table_dataset_add_index(table_set, $idx.type);
+ @end@
+
+ @foreach $c column@
+ /* adding column $c of type $c.type and access of $c.access */
+ DEBUGMSGTL(("initialize_table_$i",
+ "adding column $c.label (#$c.subid) of type $c.type to table $i\n"));
+ table_set_add_default_row(table_set, COLUMN_$c.uc, $c.type, $c.settable);
+ @end@
+
+ /* registering the table with the master agent */
+ /* note: if you don't need a subhandler to deal with any aspects
+ of the request, change ${i}_handler to "NULL" */
+ register_table_data_set(create_handler_registration("$i", ${i}_handler,
+ ${i}_oid,
+ ${i}_oid_len,
+ HANDLER_CAN_RWRITE),
+ table_set, NULL);
+}
+@end@
+
+/** Initialzies the $name module */
+void
+init_$name(void)
+{
+
+ /* here we initialize all the tables we're planning on supporting */
+ @foreach $i table@
+ initialize_table_$i();
+ @end@
+}
+@foreach $i table@
+
+/** handles requests for the $i table, if anything else needs to be done */
+int
+${i}_handler(
+ mib_handler *handler,
+ handler_registration *reginfo,
+ agent_request_info *reqinfo,
+ request_info *requests) {
+ /* perform anything here that you need to do. The requests have
+ already been processed by the master table_dataset handler, but
+ this gives you chance to act on the request in some other way
+ if need be. */
+ return SNMP_ERR_NOERROR;
+}
diff --git a/local/mib2c.iterate.conf b/local/mib2c.iterate.conf
new file mode 100644
index 0000000..59c8be1
--- /dev/null
+++ b/local/mib2c.iterate.conf
@@ -0,0 +1,241 @@
+## -*- c -*-
+######################################################################
+## Do the .h file
+######################################################################
+@open ${name}.h@
+/* Note: this file originally auto-generated by mib2c */
+#ifndef $name.uc_H
+#define $name.uc_H
+
+/* function declarations */
+void init_$name(void);
+@foreach $i table@
+void initialize_table_$i(void);
+NodeHandler ${i}_handler;
+
+FirstDataPoint ${i}_get_first_data_point;
+NextDataPoint ${i}_get_next_data_point;
+@end@
+@foreach $i table@
+
+/* column number definitions for table $i */
+ @foreach $c column@
+ #define COLUMN_$c.uc $c.subid
+ @end@
+@end@
+#endif /* $name.uc_H */
+######################################################################
+## Do the .c file
+######################################################################
+@open ${name}.c@
+/* Note: this file originally auto-generated by mib2c */
+
+#include <config.h>
+
+#include "mibincl.h"
+#include "snmp_loging.h"
+#include <helpers/table.h>
+#include <helpers/table_iterator.h>
+#include "${name}.h"
+
+@foreach $i table@
+/** Initialize the $i table by defining it's contents and how it's structured */
+void
+initialize_table_$i(void)
+{
+ static oid ${i}_oid[] = {$i.commaoid};
+ size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
+ table_registration_info *table_info;
+ handler_registration *my_handler;
+
+ /* create the table structure itself */
+ table_info = SNMP_MALLOC_TYPEDEF(table_registration_info);
+
+ /* if your table is read only, it's easiest to change the
+ HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
+ my_handler = create_handler_registration("$i",
+ ${i}_handler,
+ ${i}_oid,
+ sizeof(${i}_oid)/sizeof(oid),
+ HANDLER_CAN_RWRITE);
+
+ if (!my_handler || !table_info)
+ return; /* mallocs failed */
+
+ /***************************************************
+ * Setting up the table's definition
+ */
+ @foreach $idx index@
+ table_helper_add_index(table_info, $idx.type); /* index: $idx */
+ @end@
+
+ @eval $minv = 0xffffffff@
+ @eval $maxv = 0@
+ @foreach $c column@
+ @eval $minv = min($minv, $c.subid)@
+ @eval $maxv = max($maxv, $c.subid)@
+ @end@
+ table_info->min_column = $minv;
+ table_info->max_column = $maxv;
+ table_info->get_first_data_point = ${i}_get_first_data_point;
+ table_info->get_next_data_point = ${i}_get_next_data_point;
+
+ /***************************************************
+ * registering the table with the master agent
+ */
+ DEBUGMSGTL(("initialize_table_$i",
+ "Registering table $i as a table iterator\n"));
+ register_table_iterator(my_handler, table_info);
+}
+@end@
+
+/** Initialzies the $name module */
+void
+init_$name(void)
+{
+
+ /* here we initialize all the tables we're planning on supporting */
+ @foreach $i table@
+ initialize_table_$i();
+ @end@
+}
+@foreach $i table@
+
+/** returns the first data point within the $i table data.
+
+ Set the my_loop_context variable to the first data point structure
+ of your choice (from which you can find the next one). This could
+ be anything from the first node in a linked list, to an integer
+ pointer containing the beginning of an array variable.
+
+ Set the my_data_context variable to something to be returned to
+ you later that will provide you with the data to return in a given
+ row. This could be the same pointer as what my_loop_context is
+ set to, or something different.
+
+ The put_index_data variable contains a list of snmp variable
+ bindings, one for each index in your table. Set the values of
+ each appropriately according to the data matching the first row
+ and return the put_index_data variable at the end of the function.
+*/
+struct variable_list *
+${i}_get_first_data_point(void **my_loop_context, void **my_data_context,
+ struct variable_list *put_index_data) {
+
+ struct variable_list *vptr;
+
+ *my_loop_context = /* XXX */;
+ *my_data_context = /* XXX */;
+
+ vptr = put_index_data;
+
+ @foreach $idx index@
+ snmp_set_var_value(vptr, (u_char *) /* XXX: $idx data */, /* XXX: length of $idx data */);
+ vptr = vptr->next_variable;
+ @end@
+
+ return put_index_data;
+}
+
+/** functionally the same as ${i}_get_first_data_point, but
+ my_loop_context has already been set to a previous value and should
+ be updated to the next in the list. For example, if it was a
+ linked list, you might want to cast it and the return
+ my_loop_context->next. The my_data_context pointer should be set
+ to something you need later and the indexes in put_index_data
+ updated again. */
+
+struct variable_list *
+${i}_get_next_data_point(void **my_loop_context, void **my_data_context,
+ struct variable_list *put_index_data) {
+
+ struct variable_list *vptr;
+
+ *my_loop_context = /* XXX */;
+ *my_data_context = /* XXX */;
+
+ vptr = put_index_data;
+
+ @foreach $idx index@
+ snmp_set_var_value(vptr, (u_char *) /* XXX: $idx data */, /* XXX: length of $idx data */);
+ vptr = vptr->next_variable;
+ @end@
+
+ return put_index_data;
+}
+
+/** handles requests for the $i table, if anything else needs to be done */
+int
+${i}_handler(
+ mib_handler *handler,
+ handler_registration *reginfo,
+ agent_request_info *reqinfo,
+ request_info *requests) {
+
+ table_request_info *table_info;
+ struct variable_list *var;
+
+ while(requests) {
+ var = requests->requestvb;
+ if (requests->processed != 0)
+ continue;
+
+ /* perform anything here that you need to do. The requests have
+ already been processed by the master table_dataset handler, but
+ this gives you chance to act on the request in some other way
+ if need be. */
+
+ /* the following extracts the my_data_context pointer set in
+ the loop functions above. You can then use the results to
+ help return data for the columns of the $i table in question */
+ /* XXX */ = (/* XXX */ *) extract_iterator_context(requests);
+ if (/* XXX */ == NULL) {
+ if (reqinfo->mode == MODE_GET) {
+ set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
+ continue;
+ }
+ /* XXX: no row existed, if you support creation and this is a
+ set, start dealing with it here, else continue */
+ }
+
+ /* extracts the information about the table from the request */
+ table_info = extract_table_info(requests);
+ /* table_info->colnum contains the column number requested */
+ /* table_info->indexes contains a linked list of snmp variable
+ bindings for the indexes of the table. Values in the list
+ have been set corresponding to the indexes of the
+ request */
+ if (table_info==NULL) {
+ requests = requests->next;
+ continue;
+ }
+
+ switch(reqinfo->mode) {
+ /* the table_iterator helper should change all GETNEXTs
+ into GETs for you automatically, so you don't have to
+ worry about the GETNEXT case. Only GETs and SETs need
+ to be dealt with here */
+ case MODE_GET:
+ switch(table_info->colnum) {
+ @foreach $c column@
+ case COLUMN_$c.uc:
+ snmp_set_var_typed_value(var, $c.type, (u_char *) /* XXX: column data */, /* XXX: column data length */);
+ break;
+
+ @end@
+ default:
+ /* We shouldn't get here */
+ snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unknown column\n");
+ }
+ break;
+
+ case MODE_SET_RESERVE1:
+ /* set handling... */
+
+ default:
+ snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unsupported mode\n");
+ }
+ requests = requests->next;
+ }
+ return SNMP_ERR_NOERROR;
+}
diff --git a/local/mib2c.vartypes.conf b/local/mib2c.vartypes.conf
index 6626355..2290612 100644
--- a/local/mib2c.vartypes.conf
+++ b/local/mib2c.vartypes.conf
@@ -87,8 +87,6 @@
############################################################################
type: BITS
copy: OCTETSTR
-delete: asnType
-asnType: ASN_BIT_STR
############################################################################
type: GAUGE
copy: INTEGER
diff --git a/man/Makefile.in b/man/Makefile.in
index 53e8418..d031ec0 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -56,13 +56,20 @@
cat $(srcdir)/default_store.3.top default_store.3.h $(srcdir)/default_store.3.bot > default_store.3
install: installdirs $(MAN1) $(MAN1G) $(MAN3) $(MAN5) $(MAN5G) $(MAN8)
- @for i in $(MAN1) ; do $(INSTALL) $(srcdir)/$$i $(man1dir) ; echo "install: installed $$i in $(man1dir)" ; done
- @for i in $(MAN1G) ; do $(INSTALL) $$i $(man1dir) ; echo "install: installed $$i in $(man1dir)" ; done
- @for i in $(MAN3) ; do $(INSTALL) $(srcdir)/$$i $(man3dir) ; echo "install: installed $$i in $(man3dir)" ; done
- @for i in $(MAN3G) ; do $(INSTALL) $$i $(man3dir) ; echo "install: installed $$i in $(man3dir)" ; done
- @for i in $(MAN5) ; do $(INSTALL) $(srcdir)/$$i $(man5dir) ; echo "install: installed $$i in $(man5dir)" ; done
- @for i in $(MAN5G) ; do $(INSTALL) $$i $(man5dir) ; echo "install: installed $$i in $(man5dir)" ; done
- @for i in $(MAN8) ; do $(INSTALL) $(srcdir)/$$i $(man8dir) ; echo "install: installed $$i in $(man8dir)" ; done
+ @$(INSTALL) $(MAN1) $(man1dir)
+ @for i in $(MAN1) ; do echo "install: installed $$i in $(man1dir)" ; done
+ @$(INSTALL) $(MAN1G) $(man1dir)
+ @for i in $(MAN1G) ; do echo "install: installed $$i in $(man1dir)" ; done
+ @$(INSTALL) $(MAN3) $(man3dir)
+ @for i in $(MAN3) ; do echo "install: installed $$i in $(man3dir)" ; done
+ @$(INSTALL) $(MAN3G) $(man3dir)
+ @for i in $(MAN3G) ; do echo "install: installed $$i in $(man3dir)" ; done
+ @$(INSTALL) $(MAN5) $(man5dir)
+ @for i in $(MAN5) ; do echo "install: installed $$i in $(man5dir)" ; done
+ @$(INSTALL) $(MAN5G) $(man5dir)
+ @for i in $(MAN5G) ; do echo "install: installed $$i in $(man5dir)" ; done
+ @$(INSTALL) $(MAN8) $(man8dir)
+ @for i in $(MAN8) ; do echo "install: installed $$i in $(man8dir)" ; done
html: $(MANALL)
for i in $(MANALL); do base=`echo $$i | sed 's/.[0-9]$$//;'` ; echo "<HTML><BODY bgcolor=\"#ffffff\" background=\"../ucd-snmp-bg3.gif\"><PRE>" > $$base.html; nroff -man $$i | man2html -bare -title "$$base manual page" >> $$base.html; done
diff --git a/mibs/Makefile.in b/mibs/Makefile.in
index ec86ba6..567ff25 100644
--- a/mibs/Makefile.in
+++ b/mibs/Makefile.in
@@ -39,7 +39,8 @@
all:
install: installdirs
- @for i in $(MIBS) ; do $(INSTALL) $(srcdir)/$$i $(mibdir) ; echo "install: installed $$i in $(mibdir)" ; done
+ @$(INSTALL) $(MIBS) $(mibdir)
+ @for i in $(MIBS) ; do echo "install: installed $$i in $(mibdir)" ; done
installdirs:
@$(SHELL) $(srcdir)/../mkinstalldirs $(mibdir)
diff --git a/mibs/NET-SNMP-AGENT-MIB.txt b/mibs/NET-SNMP-AGENT-MIB.txt
new file mode 100644
index 0000000..9d455ef
--- /dev/null
+++ b/mibs/NET-SNMP-AGENT-MIB.txt
@@ -0,0 +1,71 @@
+NET-SNMP-AGENT-MIB DEFINITIONS ::= BEGIN
+
+--
+-- defines control and monitoring structures for the net-snmp agent.
+--
+
+IMPORTS
+ OBJECT-TYPE, NOTIFICATION-TYPE, MODULE-IDENTITY,
+ Integer32, Opaque, enterprises
+ FROM SNMPv2-SMI
+
+ TEXTUAL-CONVENTION, DisplayString, TruthValue
+ FROM SNMPv2-TC;
+
+netSnmpAgentMib MODULE-IDENTITY
+ LAST-UPDATED "200101170000Z"
+ ORGANIZATION "www.net-snmp.org"
+ CONTACT-INFO
+ "Defines control and monitoring structures for the net-snmp agent.
+
+ postal: Wes Hardaker
+ P.O. Box 382
+ Davis CA 95617
+
+ email: net-snmp-coders@lists.sourceforge.net"
+ DESCRIPTION
+ "Defines control and monitoring structures for the net-snmp agent."
+ REVISION "200111030000Z"
+ DESCRIPTION
+ "First revision."
+ ::= { enterprises 8072 999 1 }
+
+nsTransactionTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NsTransactionEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "lists currently outstanding transactions in the net-snmp agent."
+ ::= { netSnmpAgentMib 1 }
+
+nsTransactionEntry OBJECT-TYPE
+ SYNTAX NsTransactionEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A row describing a given transaction."
+ INDEX { nsTransactionID }
+ ::= {nsTransactionTable 1 }
+
+NsTransactionEntry ::= SEQUENCE {
+ nsTransactionID INTEGER,
+ nsTransactionMode INTEGER
+}
+
+nsTransactionID OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The internal identifier for a given transaction."
+ ::= { nsTransactionEntry 1 }
+
+nsTransactionMode OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The mode number for the current operation being performed."
+ ::= { nsTransactionEntry 2 }
+
+END
diff --git a/perl/SNMP/SNMP.xs b/perl/SNMP/SNMP.xs
index 0f9a9ad..a7db40b 100644
--- a/perl/SNMP/SNMP.xs
+++ b/perl/SNMP/SNMP.xs
@@ -3085,7 +3085,7 @@
tmp_sv=newSVpv((char*)str_buf, len);
av_store(varbind, VARBIND_VAL_F, tmp_sv);
if (sv_timestamp)
- av_store(varbind, VARBIND_TIME_F, sv_timestamp);
+ av_store(varbind, VARBIND_TYPE_F, sv_timestamp);
XPUSHs(sv_mortalcopy(tmp_sv));
} else {
av_store(varbind, VARBIND_VAL_F, &sv_undef);
@@ -3264,7 +3264,7 @@
tmp_sv = newSVpv((char*)str_buf, len);
av_store(varbind, VARBIND_VAL_F, tmp_sv);
if (sv_timestamp)
- av_store(varbind, VARBIND_TIME_F, sv_timestamp);
+ av_store(varbind, VARBIND_TYPE_F, sv_timestamp);
XPUSHs(sv_mortalcopy(tmp_sv));
} else {
/* Return undef for this variable. */
@@ -3463,7 +3463,7 @@
tmp_sv = newSVpv((char*)str_buf, len);
av_store(varbind, VARBIND_VAL_F, tmp_sv);
if (sv_timestamp)
- av_store(varbind, VARBIND_TIME_F, SvREFCNT_inc(sv_timestamp));
+ av_store(varbind, VARBIND_TYPE_F, SvREFCNT_inc(sv_timestamp));
rv = newRV_noinc((SV *)varbind);
sv_bless(rv, gv_stashpv("SNMP::Varbind",0));
diff --git a/snmplib/Makefile.in b/snmplib/Makefile.in
index 0de2bc6..bacdb35 100644
--- a/snmplib/Makefile.in
+++ b/snmplib/Makefile.in
@@ -12,6 +12,8 @@
INSTALLHEADERS=\
asn1.h \
callback.h \
+ data_list.h \
+ oid_array.h \
default_store.h \
int64.h \
keytools.h \
@@ -42,6 +44,7 @@
snmp_debug.c tools.c snmp_logging.c \
snmpv3.c lcd_time.c keytools.c \
scapi.c callback.c default_store.c snmp_alarm.c \
+ data_list.c oid_array.c \
mt_support.c snmp_enum.c snmp-tc.c \
snprintf.c strtol.c strtoul.c \
snmp_transport.c @transport_src_list@ \
@@ -53,6 +56,7 @@
snmp_debug.o tools.o snmp_logging.o \
snmpv3.o lcd_time.o keytools.o \
scapi.o callback.o default_store.o snmp_alarm.o \
+ data_list.o oid_array.o \
mt_support.o snmp_enum.o snmp-tc.o \
snprintf.o strtol.o strtoul.o \
snmp_transport.o @transport_obj_list@ \
@@ -64,6 +68,7 @@
snmp_debug.lo tools.lo snmp_logging.lo \
snmpv3.lo lcd_time.lo keytools.lo \
scapi.lo callback.lo default_store.lo snmp_alarm.lo \
+ data_list.lo oid_array.lo \
mt_support.lo snmp_enum.lo snmp-tc.lo \
snprintf.lo strtol.lo strtoul.lo \
snmp_transport.lo @transport_lobj_list@ \
@@ -78,6 +83,7 @@
all: $(TARG)
libsnmp.$(LIB_EXTENSION)$(LIB_VERSION): ${TOBJS}
+ wait
$(LIB_LD_CMD) libsnmp.$(LIB_EXTENSION)$(LIB_VERSION) ${TOBJS}
$(RANLIB) libsnmp.$(LIB_EXTENSION)$(LIB_VERSION)
@@ -86,7 +92,8 @@
install: $(TARG) installdirs
@for i in $(TARG) ; do $(INSTALL) $$i $(libdir) ; done
- @for i in $(INSTALLHEADERS) ; do $(INSTALL) $(srcdir)/$$i $(includedir) ; echo "install: installed $$i in $(includedir)" ; done
+ @$(INSTALL) $(INSTALLHEADERS) $(includedir)
+ @for i in $(INSTALLHEADERS) ; do echo "install: installed $$i in $(includedir)" ; done
$(LIB_LDCONFIG_CMD)
../lib/libsnmp.$(LIB_EXTENSION)$(LIB_VERSION): libsnmp.$(LIB_EXTENSION)$(LIB_VERSION)
diff --git a/snmplib/mib.c b/snmplib/mib.c
index 18812c1..510a998 100644
--- a/snmplib/mib.c
+++ b/snmplib/mib.c
@@ -81,6 +81,8 @@
#include "snmp_debug.h"
#include "default_store.h"
#include "snmp_logging.h"
+#include "tools.h"
+#include "snmp_client.h"
static struct tree * _sprint_objid(char *buf, oid *objid, size_t objidlen);
@@ -3158,6 +3160,273 @@
return buf;
}
+/* takes the value in VAR and turns it into an OID segment in VAR->NAME */
+/* returns SNMPERR_SUCCESS or SNMPERR_GENERR */
+int
+build_oid_segment(struct variable_list *var) {
+ int i;
+
+ switch(var->type) {
+ case ASN_INTEGER:
+ case ASN_COUNTER:
+ case ASN_GAUGE:
+ case ASN_TIMETICKS:
+ var->name_length = 1;
+ var->name = (oid *) malloc(sizeof(oid));
+ if (var->name == NULL)
+ return SNMPERR_GENERR;
+ var->name[0] = *(var->val.integer);
+ break;
+
+ case ASN_PRIV_IMPLIED_OBJECT_ID:
+ var->name_length = var->val_len/sizeof(oid);
+ var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
+ if (var->name == NULL)
+ return SNMPERR_GENERR;
+
+ for(i = 0; i < (int)var->name_length; i++)
+ var->name[i] = var->val.objid[i];
+ break;
+
+ case ASN_OBJECT_ID:
+ var->name_length = var->val_len/sizeof(oid) + 1;
+ var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
+ if (var->name == NULL)
+ return SNMPERR_GENERR;
+
+ var->name[0] = var->name_length-1;
+ for(i = 0; i < (int)var->name_length-1; i++)
+ var->name[i+1] = var->val.objid[i];
+ break;
+
+ case ASN_PRIV_IMPLIED_OCTET_STR:
+ var->name_length = var->val_len;
+ var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
+ if (var->name == NULL)
+ return SNMPERR_GENERR;
+
+ for(i = 0; i < (int)var->val_len; i++)
+ var->name[i] = (oid) var->val.string[i];
+ break;
+
+ case ASN_OPAQUE:
+ case ASN_OCTET_STR:
+ var->name_length = var->val_len + 1;
+ var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
+ if (var->name == NULL)
+ return SNMPERR_GENERR;
+
+ var->name[0] = (oid) var->val_len;
+ for(i = 0; i < (int)var->val_len; i++)
+ var->name[i+1] = (oid) var->val.string[i];
+ break;
+
+ default:
+ DEBUGMSGTL(("build_oid_segment",
+ "invalid asn type: %d\n", var->type));
+ return SNMPERR_GENERR;
+ }
+
+ if (var->name_length > MAX_OID_LEN) {
+ DEBUGMSGTL(("build_oid_segment",
+ "Something terribly wrong, namelen = %d\n", var->name_length));
+ return SNMPERR_GENERR;
+ }
+
+ return SNMPERR_SUCCESS;
+}
+
+
+int build_oid_noalloc(oid *in, size_t in_len, size_t *out_len,
+ oid *prefix, size_t prefix_len,
+ struct variable_list *indexes)
+{
+ struct variable_list *var;
+
+ if (prefix) {
+ if (in_len < prefix_len)
+ return SNMPERR_GENERR;
+ memcpy(in, prefix, prefix_len * sizeof(oid));
+ *out_len = prefix_len;
+ } else {
+ *out_len = 0;
+ }
+
+ for(var = indexes; var != NULL; var = var->next_variable) {
+ if (build_oid_segment(var) != SNMPERR_SUCCESS)
+ return SNMPERR_GENERR;
+ if (var->name_length + *out_len < in_len) {
+ memcpy(&(in[*out_len]), var->name, sizeof(oid) * var->name_length);
+ *out_len += var->name_length;
+ } else {
+ return SNMPERR_GENERR;
+ }
+ }
+
+ DEBUGMSGTL(("build_oid_noalloc", "generated: "));
+ DEBUGMSGOID(("build_oid_noalloc", in, *out_len));
+ DEBUGMSG(("build_oid_noalloc", "\n"));
+ return SNMPERR_SUCCESS;
+}
+
+int build_oid(oid **out, size_t *out_len,
+ oid *prefix, size_t prefix_len,
+ struct variable_list *indexes)
+{
+ oid tmpout[MAX_OID_LEN];
+
+ if (build_oid_noalloc(tmpout,sizeof(tmpout), out_len,
+ prefix, prefix_len, indexes) != SNMPERR_SUCCESS)
+ return SNMPERR_GENERR;
+
+ snmp_clone_mem((void **) out, (void *) tmpout, *out_len*sizeof(oid));
+
+ return SNMPERR_SUCCESS;
+}
+
+/* vblist_out must contain a pre-allocated string of variables into
+ which indexes can be extracted based on the previously existing
+ types in the variable chain
+ returns:
+ SNMPERR_GENERR on error
+ SNMPERR_SUCCESS on success
+*/
+
+int parse_oid_indexes(oid *oidIndex, size_t oidLen,
+ struct variable_list *data)
+{
+ struct variable_list *var = data;
+
+ while(var && oidLen > 0) {
+
+ if(parse_one_oid_index(&oidIndex, &oidLen, var, 0) != SNMPERR_SUCCESS)
+ break;
+
+ var = var->next_variable;
+ }
+
+ if (var != NULL || oidLen != 0)
+ return SNMPERR_GENERR;
+ return SNMPERR_SUCCESS;
+}
+
+
+int parse_one_oid_index(oid **oidStart, size_t *oidLen,
+ struct variable_list *data, int complete)
+{
+ struct variable_list *var = data;
+ oid tmpout[MAX_OID_LEN];
+ int i, itmp;
+
+ oid *oidIndex = *oidStart;
+
+ if (var == NULL || ( (*oidLen == 0) && (complete==0) ) )
+ return SNMPERR_GENERR;
+ else {
+ switch(var->type) {
+ case ASN_INTEGER:
+ case ASN_COUNTER:
+ case ASN_GAUGE:
+ case ASN_TIMETICKS:
+ if (*oidLen) {
+ snmp_set_var_value(var, (u_char *) oidIndex++, sizeof(long));
+ --(*oidLen);
+ } else {
+ snmp_set_var_value(var, (u_char *) oidLen, sizeof(long));
+ }
+ DEBUGMSGTL(("parse_oid_indexes",
+ "Parsed int(%d): %d\n", var->type, *var->val.integer));
+ break;
+
+ case ASN_OBJECT_ID:
+ case ASN_PRIV_IMPLIED_OBJECT_ID:
+ if (var->type == ASN_PRIV_IMPLIED_OBJECT_ID) {
+ itmp = *oidLen;
+ } else {
+ if (*oidLen) {
+ itmp = (long) *oidIndex++;
+ --(*oidLen);
+ } else {
+ itmp = 0;
+ }
+ if ( (itmp > (int)*oidLen) && (complete==0) )
+ return SNMPERR_GENERR;
+ }
+
+ if (itmp > (int)*oidLen) {
+ memcpy( tmpout, oidIndex, sizeof(oid)*(*oidLen) );
+ memset( &tmpout[ *oidLen ], 0x00, sizeof(oid)*(itmp-*oidLen) );
+ snmp_set_var_value(var, (u_char *) tmpout, sizeof(oid)*itmp);
+ oidIndex += *oidLen;
+ (*oidLen) = 0;
+ } else {
+ snmp_set_var_value(var, (u_char *) oidIndex, sizeof(oid)*itmp);
+ oidIndex += itmp;
+ (*oidLen) -= itmp;
+ }
+
+ DEBUGMSGTL(("parse_oid_indexes", "Parsed oid: "));
+ DEBUGMSGOID(("parse_oid_indexes",
+ var->val.objid, var->val_len/sizeof(oid)));
+ DEBUGMSG(("parse_oid_indexes", "\n"));
+ break;
+
+ case ASN_OPAQUE:
+ case ASN_OCTET_STR:
+ case ASN_PRIV_IMPLIED_OCTET_STR:
+ if (var->type == ASN_PRIV_IMPLIED_OCTET_STR) {
+ itmp = *oidLen;
+ } else {
+ if (*oidLen) {
+ itmp = (long) *oidIndex++;
+ --(*oidLen);
+ } else {
+ itmp = 0;
+ }
+ if ( (itmp > (int)*oidLen) && (complete==0) )
+ return SNMPERR_GENERR;
+ }
+
+ /* we handle this one ourselves since we don't have
+ pre-allocated memory to copy from using
+ snmp_set_var_value() */
+
+ if (itmp == 0)
+ break; /* zero length strings shouldn't malloc */
+
+ /* malloc by size+1 to allow a null to be appended. */
+ var->val_len = itmp;
+ var->val.string = (u_char *) calloc(1,itmp+1);
+ if (var->val.string == NULL)
+ return SNMPERR_GENERR;
+
+ if (itmp > (int)(*oidLen) ) {
+ for(i = 0; i < *oidLen; ++i)
+ var->val.string[i] = (u_char) *oidIndex++;
+ for(i = 0; i < itmp; ++i)
+ var->val.string[i] = '\0';
+ (*oidLen) = 0;
+ } else {
+ for(i = 0; i < itmp; ++i)
+ var->val.string[i] = (u_char) *oidIndex++;
+ (*oidLen) -= itmp;
+ }
+ var->val.string[itmp] = '\0';
+
+ DEBUGMSGTL(("parse_oid_indexes",
+ "Parsed str(%d): %s\n", var->type, var->val.string));
+ break;
+
+ default:
+ DEBUGMSGTL(("parse_oid_indexes",
+ "invalid asn type: %d\n", var->type));
+ return SNMPERR_GENERR;
+ }
+ }
+ (*oidStart) = oidIndex;
+ return SNMPERR_SUCCESS;
+}
+
int
dump_realloc_oid_to_string(oid *objid, size_t objidlen,
u_char **buf, size_t *buf_len, size_t *out_len,
@@ -4678,6 +4947,58 @@
return NULL;
}
+int
+mib_to_asn_type(int mib_type)
+{
+ switch(mib_type) {
+ case TYPE_OBJID:
+ return ASN_OBJECT_ID;
+
+ case TYPE_OCTETSTR:
+ case TYPE_IPADDR:
+ return ASN_OCTET_STR;
+
+ case TYPE_NETADDR:
+ return ASN_IPADDRESS;
+
+ case TYPE_INTEGER32:
+ case TYPE_INTEGER:
+ return ASN_INTEGER;
+
+ case TYPE_COUNTER:
+ return ASN_COUNTER;
+
+ case TYPE_GAUGE:
+ return ASN_COUNTER;
+
+ case TYPE_TIMETICKS:
+ return ASN_TIMETICKS;
+
+ case TYPE_OPAQUE:
+ return ASN_OPAQUE;
+
+ case TYPE_NULL:
+ return ASN_NULL;
+
+ case TYPE_COUNTER64:
+ return ASN_COUNTER64;
+
+ case TYPE_BITSTRING:
+ return ASN_BIT_STR;
+
+ case TYPE_UINTEGER:
+ case TYPE_UNSIGNED32:
+ return ASN_UINTEGER;
+
+ case TYPE_NSAPADDRESS:
+ return ASN_NSAP;
+
+ }
+ return -1;
+}
+
+
+
#ifdef CMU_COMPATIBLE
int mib_TxtToOid(char *Buf, oid **OidP, size_t *LenP)
diff --git a/snmplib/mib.h b/snmplib/mib.h
index ff1e76f..25a7bee 100644
--- a/snmplib/mib.h
+++ b/snmplib/mib.h
@@ -32,6 +32,8 @@
SOFTWARE.
******************************************************************/
+#include <stdio.h> /* for FILE */
+
#ifdef CMU_COMPATIBLE
struct mib_system {
@@ -358,6 +360,16 @@
const char *, const char *);
#endif
+int parse_one_oid_index(oid **oidStart, size_t *oidLen,
+ struct variable_list *data, int complete);
+int parse_oid_indexes(oid *oidIndex, size_t oidLen, struct variable_list *data);
+int build_oid_noalloc(oid *in, size_t in_len, size_t *out_len,
+ oid *prefix, size_t prefix_len,
+ struct variable_list *indexes);
+int build_oid(oid **out, size_t *out_len, oid *prefix, size_t prefix_len,
+ struct variable_list *indexes);
+int build_oid_segment(struct variable_list *var);
+
int sprint_realloc_hexstring (u_char **buf, size_t *buf_len,
size_t *out_len, int allow_realloc,
const u_char *, size_t);
@@ -474,6 +486,7 @@
void snmp_out_toggle_options_usage(const char *, FILE *);
char *snmp_in_toggle_options(char *);
void snmp_in_toggle_options_usage(const char *, FILE *);
+int mib_to_asn_type(int mib_type);
#ifdef __cplusplus
}
diff --git a/snmplib/read_config.c b/snmplib/read_config.c
index 9737fe4..1f8266b 100644
--- a/snmplib/read_config.c
+++ b/snmplib/read_config.c
@@ -1136,6 +1136,7 @@
}
} else {
readfrom = copy_nword(readfrom, (char *)*str, *len);
+ *len = strlen(*str);
}
}
@@ -1199,6 +1200,9 @@
Returns: character pointer to the next token in the configuration line.
NULL if none left.
NULL if an unknown type.
+
+ dataptr is expected to match a pointer type being read
+ (int *, u_int *, char **, oid **)
*/
char *read_config_read_data(int type, char *readfrom, void *dataptr, size_t *len) {
int *intp;
@@ -1236,8 +1240,59 @@
return NULL;
}
-/* read_config_read_data():
- reads data of a given type from a token(s) on a configuration line.
+/* read_config_read_memory():
+
+ similar to read_config_read_data, but expects a generic memory
+ pointer rather than a specific type of pointer. Len is expected to
+ be the amount of available memory.
+*/
+char *read_config_read_memory(int type, char *readfrom,
+ char *dataptr, size_t *len) {
+ int *intp;
+ unsigned int *uintp;
+
+ if (!dataptr || !readfrom)
+ return NULL;
+
+ switch(type) {
+ case ASN_INTEGER:
+ if (*len < sizeof(int))
+ return NULL;
+ intp = (int *) dataptr;
+ *intp = atoi(readfrom);
+ *len = sizeof(int);
+ readfrom = skip_token(readfrom);
+ return readfrom;
+
+ case ASN_UNSIGNED:
+ if (*len < sizeof(unsigned int))
+ return NULL;
+ uintp = (unsigned int *) dataptr;
+ *uintp = strtoul(readfrom, NULL, 0);
+ *len = sizeof(unsigned int);
+ readfrom = skip_token(readfrom);
+ return readfrom;
+
+ case ASN_OCTET_STR:
+ case ASN_BIT_STR:
+ case ASN_PRIV_IMPLIED_OCTET_STR:
+ return read_config_read_octet_string(readfrom, (u_char **) &dataptr, len);
+
+ case ASN_PRIV_IMPLIED_OBJECT_ID:
+ case ASN_OBJECT_ID:
+ readfrom = read_config_read_objid(readfrom, (oid **) &dataptr, len);
+ *len *= sizeof(oid);
+ return readfrom;
+
+ default:
+ DEBUGMSGTL(("read_config_read_memory","Fail: Unknown type: %d", type));
+ return NULL;
+ }
+ return NULL;
+}
+
+/* read_config_store_data():
+ stores data of a given type to a configuration line.
Returns: character pointer to the next token in the configuration line.
NULL if none left.
diff --git a/snmplib/read_config.h b/snmplib/read_config.h
index 87bfe0e..2f1c352 100644
--- a/snmplib/read_config.h
+++ b/snmplib/read_config.h
@@ -84,6 +84,7 @@
char *read_config_read_objid(char *readfrom, oid **objid, size_t *len);
char *read_config_save_objid(char *saveto, oid *objid, size_t len);
char *read_config_read_data(int type, char *readfrom, void *dataptr, size_t *len);
+char *read_config_read_memory(int type, char *readfrom, char *dataptr, size_t *len);
char *read_config_store_data(int type, char *storeto, void *dataptr, size_t *len);
void read_config_store(const char *type, const char *line);
void read_app_config_store(const char *line);
diff --git a/snmplib/snmp-tc.h b/snmplib/snmp-tc.h
index 6623a9d..c022c10 100644
--- a/snmplib/snmp-tc.h
+++ b/snmplib/snmp-tc.h
@@ -15,6 +15,7 @@
#define TV_FALSE 2
/* RowStatus */
+#define RS_NONEXISTENT 0
#define RS_ACTIVE 1
#define RS_NOTINSERVICE 2
#define RS_NOTREADY 3
@@ -22,13 +23,21 @@
#define RS_CREATEANDWAIT 5
#define RS_DESTROY 6
+#define RS_IS_GOING_ACTIVE( x ) ( x == RS_CREATEANDGO || x == RS_ACTIVE )
+#define RS_IS_ACTIVE( x ) ( x == RS_ACTIVE )
+#define RS_IS_NOT_ACTIVE( x ) ( ! RS_GOING_ACTIVE(x) )
+
/* StorageType */
+#define ST_NONE 0
#define ST_OTHER 1
#define ST_VOLATILE 2
#define ST_NONVOLATILE 3
#define ST_PERMANENT 4
#define ST_READONLY 5
+char check_rowstatus_transition( int old_val, int new_val, int storage_type );
+char check_storage_transition( int old_val, int new_val );
+
#ifdef __cplusplus
}
#endif
diff --git a/snmplib/snmpUnixDomain.h b/snmplib/snmpUnixDomain.h
index 2da2eb1..d4e5fae 100644
--- a/snmplib/snmpUnixDomain.h
+++ b/snmplib/snmpUnixDomain.h
@@ -17,6 +17,12 @@
snmp_transport *snmp_unix_transport (struct sockaddr_un *addr,
int local);
+int snmp_unix_recv (snmp_transport *t, void *buf, int size,
+ void **opaque, int *olength);
+int snmp_unix_send (snmp_transport *t, void *buf, int size,
+ void **opaque, int *olength);
+int snmp_unix_close (snmp_transport *t);
+int snmp_unix_accept (snmp_transport *t);
/* "Constructor" for transport domain object. */
diff --git a/snmplib/snmp_api.c b/snmplib/snmp_api.c
index 96975ec..b0ef766 100644
--- a/snmplib/snmp_api.c
+++ b/snmplib/snmp_api.c
@@ -188,6 +188,8 @@
int (*hook_realloc_build)(struct snmp_session *, struct snmp_pdu *,
u_char **, size_t *, size_t *);
int (*check_packet) (u_char *, size_t);
+ struct snmp_pdu * (*hook_create_pdu) (snmp_transport *,
+ void *, size_t);
u_char *packet;
size_t packet_len, packet_size;
@@ -1178,7 +1180,36 @@
struct session_list *slp;
slp = (struct session_list *)snmp_sess_add_ex(in_session, transport,
fpre_parse, NULL, fpost_parse,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
+ if (slp == NULL) {
+ return NULL;
+ }
+
+ snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
+ slp->next = Sessions;
+ Sessions = slp;
+ snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
+
+ return (slp->session);
+}
+
+struct snmp_session *snmp_add_full(
+struct snmp_session *in_session,
+snmp_transport *transport,
+int (*fpre_parse) (struct snmp_session *, snmp_transport *, void *, int),
+int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t),
+int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int),
+int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
+int (*frbuild)(struct snmp_session *, struct snmp_pdu *, u_char **,
+ size_t *, size_t *),
+int (*fcheck) (u_char *, size_t),
+struct snmp_pdu * (*fcreate_pdu) (snmp_transport *, void *, size_t))
+{
+ struct session_list *slp;
+ slp = (struct session_list *)snmp_sess_add_ex(in_session, transport,
+ fpre_parse, fparse, fpost_parse,
+ fbuild, frbuild,
+ fcheck, fcreate_pdu);
if (slp == NULL) {
return NULL;
}
@@ -1202,7 +1233,8 @@
int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
int (*frbuild)(struct snmp_session *, struct snmp_pdu *, u_char **,
size_t *, size_t *),
-int (*fcheck) (u_char *, size_t))
+int (*fcheck) (u_char *, size_t),
+struct snmp_pdu * (*fcreate_pdu) (snmp_transport *, void *, size_t))
{
struct session_list *slp;
@@ -1227,6 +1259,7 @@
slp->internal->hook_build = fbuild;
slp->internal->hook_realloc_build = frbuild;
slp->internal->check_packet = fcheck;
+ slp->internal->hook_create_pdu = fcreate_pdu;
slp->session->rcvMsgMaxSize = transport->msgMaxSize;
@@ -1251,7 +1284,7 @@
int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int))
{
return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
- fpost_parse, NULL, NULL, NULL);
+ fpost_parse, NULL, NULL, NULL, NULL);
}
@@ -4105,6 +4138,27 @@
free((char *)pdu);
}
+struct snmp_pdu *
+snmp_create_sess_pdu(snmp_transport *transport, void *opaque, size_t olength)
+{
+ struct snmp_pdu *pdu;
+ pdu = (struct snmp_pdu *)calloc(1,sizeof(struct snmp_pdu));
+ if (pdu == NULL) {
+ DEBUGMSGTL(("sess_process_packet", "can't malloc space for PDU\n"));
+ return NULL;
+ }
+
+ /* Save the transport-level data specific to this reception (e.g. UDP
+ source address). */
+
+ pdu->transport_data = opaque;
+ pdu->transport_data_length = olength;
+ pdu->tDomain = transport->domain;
+ pdu->tDomainLen = transport->domain_length;
+ return pdu;
+}
+
+
/* This function processes a complete (according to asn_check_packet or the
AgentX equivalent) packet, parsing it into a PDU and calling the relevant
callbacks. On entry, packetptr points at the packet in the session's
@@ -4149,19 +4203,15 @@
}
}
- pdu = (struct snmp_pdu *)calloc(1,sizeof(struct snmp_pdu));
- if (pdu == NULL) {
- DEBUGMSGTL(("sess_process_packet", "can't malloc space for PDU\n"));
- return -1;
+ if (isp->hook_create_pdu) {
+ pdu = isp->hook_create_pdu(transport, opaque, olength);
+ } else {
+ pdu = snmp_create_sess_pdu(transport, opaque, olength);
}
-
- /* Save the transport-level data specific to this reception (e.g. UDP
- source address). */
-
- pdu->transport_data = opaque;
- pdu->transport_data_length = olength;
- pdu->tDomain = transport->domain;
- pdu->tDomainLen = transport->domain_length;
+ if (!pdu) {
+ snmp_log(LOG_ERR, "pdu failed to be created\n");
+ return -1;
+ }
if (isp->hook_parse) {
ret = isp->hook_parse(sp, pdu, packetptr, length);
@@ -4412,7 +4462,8 @@
nslp = (struct session_list *)snmp_sess_add_ex(sp, new_transport,
isp->hook_pre, isp->hook_parse,
isp->hook_post, isp->hook_build,
- isp->hook_realloc_build, isp->check_packet);
+ isp->hook_realloc_build, isp->check_packet,
+ isp->hook_create_pdu);
if (nslp != NULL) {
nslp->next = Sessions;
@@ -5019,6 +5070,12 @@
}
}
+int
+snmp_oid_ncompare(const oid *in_name1, const oid*in_name2, int len)
+{
+ return snmp_oid_compare(in_name1, len, in_name2, len);
+}
+
/* lexicographical compare two object identifiers.
* Returns -1 if name1 < name2,
* 0 if name1 = name2,
diff --git a/snmplib/snmp_api.h b/snmplib/snmp_api.h
index ee6ebb9..ac72c8b 100644
--- a/snmplib/snmp_api.h
+++ b/snmplib/snmp_api.h
@@ -743,7 +743,8 @@
snmp_pdu *, u_char *, size_t *),
int (*frbuild)(struct snmp_session *, struct
snmp_pdu *, u_char **, size_t *, size_t *),
- int (*fcheck) (u_char *, size_t));
+ int (*fcheck) (u_char *, size_t),
+ struct snmp_pdu * (*fcreate_pdu) (struct _snmp_transport *, void *, size_t));
void *snmp_sess_add (struct snmp_session *, struct _snmp_transport *,
int (*fpre_parse) (struct snmp_session *,
@@ -758,6 +759,16 @@
void *, int),
int (*fpost_parse) (struct snmp_session *,
struct snmp_pdu *, int));
+struct snmp_session *snmp_add_full(struct snmp_session *in_session,
+ struct _snmp_transport *transport,
+ int (*fpre_parse) (struct snmp_session *, struct _snmp_transport *, void *, int),
+ int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t),
+ int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int),
+ int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
+ int (*frbuild)(struct snmp_session *, struct snmp_pdu *, u_char **, size_t *, size_t *),
+ int (*fcheck) (u_char *, size_t),
+ struct snmp_pdu * (*fcreate_pdu) (struct _snmp_transport *, void *, size_t)
+);
/* use return value from snmp_sess_open as void * parameter */
@@ -832,7 +843,13 @@
#define STAT_SNMP_STATS_START STAT_SNMPINPKTS
#define STAT_SNMP_STATS_END STAT_SNMPOUTTRAPS
-#define MAX_STATS 41
+/* target mib counters */
+#define STAT_SNMPUNAVAILABLECONTEXTS 41
+#define STAT_SNMPUNKNOWNCONTEXTS 42
+#define STAT_TARGET_STATS_START STAT_SNMPUNAVAILABLECONTEXTS
+#define STAT_TARGET_STATS_END STAT_SNMPUNKNOWNCONTEXTS
+
+#define MAX_STATS 43
#ifdef __cplusplus
}
diff --git a/snmplib/snmp_client.c b/snmplib/snmp_client.c
index b94c9e2..001d35b 100644
--- a/snmplib/snmp_client.c
+++ b/snmplib/snmp_client.c
@@ -265,6 +265,28 @@
/*
+ * Walks through a list of varbinds and frees and allocated memory,
+ * restoring pointers to local buffers
+ */
+void
+snmp_reset_var_buffers( struct variable_list * var )
+{
+ while( var ) {
+ if(var->name != var->name_loc) {
+ free(var->name);
+ var->name = var->name_loc;
+ var->name_length = 0;
+ }
+ if(var->val.string != var->buf) {
+ free(var->val.string);
+ var->val.string = var->buf;
+ var->val_len = 0;
+ }
+ var = var->next_variable;
+ }
+}
+
+/*
* Creates and allocates a clone of the input PDU,
* but does NOT copy the variables.
* This function should be used with another function,
@@ -571,7 +593,8 @@
vp->name = (oid *)malloc(len);
if (!vp->name) return 1;
}
- memmove(vp->name, objid, len);
+ if (objid)
+ memmove(vp->name, objid, len);
vp->name_length = name_length;
return 0;
}
@@ -584,6 +607,38 @@
return snmp_set_var_value(newvar, val_str, val_len);
}
+int
+count_varbinds( struct variable_list *var_ptr )
+{
+ int count = 0;
+
+ for ( ; var_ptr != NULL ; var_ptr = var_ptr->next_variable )
+ count++;
+
+ return count;
+}
+
+int
+count_varbinds_of_type( struct variable_list *var_ptr, int type )
+{
+ int count = 0;
+
+ for (; var_ptr != NULL ; var_ptr = var_ptr->next_variable )
+ if (var_ptr->type == type)
+ count++;
+
+ return count;
+}
+
+struct variable_list *
+find_varbind_of_type( struct variable_list *var_ptr, int type )
+{
+ for (; var_ptr != NULL && var_ptr->type != type ;
+ var_ptr = var_ptr->next_variable );
+
+ return var_ptr;
+}
+
/*
* Add some value to SNMP variable.
* If the value is large, additional memory is allocated.
@@ -613,8 +668,12 @@
}
memmove(newvar->val.string, val_str, val_len);
newvar->val_len = val_len;
+ } else if (val_str) {
+ /* NULL STRING != NULL ptr */
+ newvar->val.string = newvar->buf;
+ newvar->val.string[0] = '\0';
+ newvar->val_len = 0;
}
-
return 0;
}
diff --git a/snmplib/snmp_client.h b/snmplib/snmp_client.h
index 011a43c..c338bbd 100644
--- a/snmplib/snmp_client.h
+++ b/snmplib/snmp_client.h
@@ -53,7 +53,12 @@
u_char *val_str, size_t val_len);
void snmp_replace_var_types(struct variable_list *vbl, int old_type,
int new_type);
+void snmp_reset_var_buffers( struct variable_list * var );
void snmp_reset_var_types(struct variable_list *vbl, int new_type);
+int count_varbinds( struct variable_list *var_ptr );
+int count_varbinds_of_type( struct variable_list *var_ptr, int type );
+struct variable_list *find_varbind_of_type( struct variable_list *var_ptr,
+ int type );
struct variable_list* snmp_add_null_var (struct snmp_pdu *, oid *, size_t);
struct snmp_pdu *snmp_pdu_create (int);
diff --git a/snmplib/snmp_transport.c b/snmplib/snmp_transport.c
index fa2c6d8..22b41e6 100644
--- a/snmplib/snmp_transport.c
+++ b/snmplib/snmp_transport.c
@@ -29,6 +29,7 @@
#include "snmp_api.h"
#include "snmp_debug.h"
#include "snmp_logging.h"
+#include "tools.h"
/* Our list of supported transport domains. */
@@ -333,3 +334,49 @@
free(mystring);
return NULL;
}
+
+
+/** adds a transport to a linked list of transports.
+ Returns 1 on failure, 0 on success */
+int
+snmp_transport_add_to_list(snmp_transport_list **transport_list,
+ snmp_transport *transport) {
+ snmp_transport_list *newptr = SNMP_MALLOC_TYPEDEF(snmp_transport_list);
+
+ if (!newptr)
+ return 1;
+
+ newptr->next = *transport_list;
+ newptr->transport = transport;
+
+ *transport_list = newptr;
+
+ return 0;
+}
+
+
+/** removes a transport from a linked list of transports.
+ Returns 1 on failure, 0 on success */
+int
+snmp_transport_remove_from_list(snmp_transport_list **transport_list,
+ snmp_transport *transport) {
+ snmp_transport_list *ptr = *transport_list, *lastptr = NULL;
+
+ while(ptr && ptr->transport != transport) {
+ lastptr = ptr;
+ ptr = ptr->next;
+ }
+
+ if (!ptr)
+ return 1;
+
+ if (lastptr)
+ lastptr->next = ptr->next;
+ else
+ *transport_list = ptr->next;
+
+ free(ptr);
+
+ return 0;
+}
+
diff --git a/snmplib/snmp_transport.h b/snmplib/snmp_transport.h
index a0c89e4..4bb6948 100644
--- a/snmplib/snmp_transport.h
+++ b/snmplib/snmp_transport.h
@@ -79,11 +79,15 @@
char *(*f_fmtaddr) (struct _snmp_transport *, void *, int);
} snmp_transport;
+typedef struct snmp_transport_list_s {
+ snmp_transport *transport;
+ struct snmp_transport_list_s *next;
+} snmp_transport_list;
+
typedef struct _snmp_tdomain {
const oid *name;
size_t name_length;
const char **prefix;
-
snmp_transport *(*f_create)(const char *, int);
struct _snmp_tdomain *next;
@@ -92,6 +96,11 @@
/* Some utility functions. */
+int snmp_transport_add_to_list(snmp_transport_list **transport_list,
+ snmp_transport *transport);
+int snmp_transport_remove_from_list(snmp_transport_list **transport_list,
+ snmp_transport *transport);
+
/* Return an exact (deep) copy of t, or NULL if there is a memory allocation
problem (for instance). */
diff --git a/snmplib/tools.c b/snmplib/tools.c
index def2ec4..0b62dc9 100644
--- a/snmplib/tools.c
+++ b/snmplib/tools.c
@@ -714,3 +714,26 @@
return 1;
}
+
+
+ /*
+ * Time-related utility functions
+ */
+
+ /* Return the number of timeTicks since the given marker */
+int
+marker_tticks( marker_t pm )
+{
+ int res;
+ marker_t now = atime_newMarker();
+
+ res = atime_diff( pm, now );
+ free( now );
+ return res/10; /* atime_diff works in msec, not csec */
+}
+
+int timeval_tticks( struct timeval *tv )
+{
+ return marker_tticks((marker_t)tv);
+}
+
diff --git a/snmplib/tools.h b/snmplib/tools.h
index ddc1f94..6401365 100644
--- a/snmplib/tools.h
+++ b/snmplib/tools.h
@@ -148,6 +148,9 @@
long atime_diff( marker_t first, marker_t second );
int atime_ready( marker_t pm, int deltaT);
+int marker_tticks( marker_t pm );
+int timeval_tticks( struct timeval *tv );
+
#ifdef __cplusplus
}
#endif
diff --git a/snmplib/vacm.c b/snmplib/vacm.c
index 8e482de..ac87acc 100644
--- a/snmplib/vacm.c
+++ b/snmplib/vacm.c
@@ -537,7 +537,13 @@
if ((securityModel == vp->securityModel || vp->securityModel == SNMP_SEC_MODEL_ANY)
&& securityLevel >= vp->securityLevel
&& !memcmp(vp->groupName, group, glen+1)
- && !memcmp(vp->contextPrefix, context, clen+1))
+ && ((vp->contextMatch == CONTEXT_MATCH_EXACT
+ && clen == vp->contextPrefix[0]
+ && (memcmp(vp->contextPrefix, context, clen+1) == 0))
+ || (vp->contextMatch == CONTEXT_MATCH_PREFIX
+ && clen >= vp->contextPrefix[0]
+ && (memcmp(vp->contextPrefix + 1, context + 1,
+ vp->contextPrefix[0]) == 0))))
return vp;
}
return NULL;