Hello.

 

I'm attempting to understand the basics of using mib2c to

generate sub-agent code for MIB tables. I have reached a point

where I need to request help.

 

Prior to this I have had success developing simple, though high

volume, private MIBs employing scalars; first with an integer only

experiment using "mib2c.int_watch.conf" then a combined integer

and string example using "mib2c.scalar.conf".

 

The table experiment involves a simple table of integers, conceptually

identical to "int my_array[256]". After some hacking I have gotten the

subagent to run and attach to the agent. And I can generate some

obvious activity. Unfortunately, my knowledge of NetSnmp debug

technique is quite weak; you may wish to suggest some readings (web or

otherwise) that I should pursue.

 

 

The following items comprise the pieces of the experiment:

(Each can be found, successively, by searching on "***PIECE #")

 

1) the MIB and its snmptranslate

 

   I have very spotty knowledge of MIB writing; e.g. I was most surprised

   to find that mib2c ignored my table until I renamed it so as to have it

   end with the character string "Table".

 

2) the 3 files generated by

 

    mib2c -c mib2c.array-user.conf test4Master

    mib2c -c subagent.m2c test4Master

 

  Note: I have attempted to make my modifications evident by

  use of the tag "RJW"

 

3) the Makefile (adapted from a NetSnmp tutorial Makefile)

 

4) the subagent execution and snmp tool results against it.

 

This is the simplest possible array example I could dream up.

If we can get it working, I'd be delighted to donate it to your

group for use by other first-timers.

 

If you are willing to look at this, I'd appreciate it. If you

need more/different info (e.g. according to "snmpd -v"

we are using: NET-SNMP version:  5.3.0.1), just let me know.

 

 

***PIECE #1: the MIB and its snmptranslate

------------------------------------------

 

     1  --------------------------------------------------------------------------------

     2  --                                                                            --

     3  --                                                                            --

     4  --                                                                            --

     5  --                                                                            --

     6  -- Copyright (C) 2006, 2007 ASSETT, Inc.                                      --

     7  -- Copyright (C) 2006, 2007                                                   --

     8  -- Copyright (C) 2006, 2007                                                   --

     9  --                                                                            --

    10  -- Proprietary and Confidential                                               --

    11  --                                                                            --

    12  --------------------------------------------------------------------------------

    13  --                                                                            --

    14  -- MODULE: TPS MIB Tree Definition                                            --

    15  --                                                                            --

    16  --------------------------------------------------------------------------------

    17  --                                                                            --

    18  -- $Header: /home/cvsroot/sdhs/startup/snmp/NET-SNMP-S80TPS-MIB.txt,v 1.6 2007/02/01 16:42:25 plunkett Exp $

    19  --                                                                            --

    20  --------------------------------------------------------------------------------

    21  --! \file netSnmpS80Tps.cpp

    22  --! \brief TPS MIB Tree

    23  --!

    24  --! \author Robert Walter

    25  --! \ingroup startup

    26  --------------------------------------------------------------------------------

    27

    28  ROB-TEST4-MIB DEFINITIONS ::= BEGIN

    29

    30  -- MIB objects for managed items specific to S80 TPS cabinet.

    31

    32  IMPORTS

    33      MODULE-IDENTITY, OBJECT-TYPE, Integer32 FROM SNMPv2-SMI

    34      SnmpAdminString                         FROM SNMP-FRAMEWORK-MIB

    35      netSnmp                                 FROM NET-SNMP-MIB

    36      RowStatus, StorageType                  FROM SNMPv2-TC

    37      InetAddressType, InetAddress            FROM INET-ADDRESS-MIB;

    38

    39  --

    40  -- A brief description and update information about this mib.

    41  --

    42  robTest4 MODULE-IDENTITY

    43      LAST-UPDATED "200704300000Z"            -- 30 Apr 2007, midnight

    44      ORGANIZATION "net-snmp"

    45      CONTACT-INFO "postal:   R. Walter, ASSETT Inc.

    46                              11220 Assett Loop

    47                              Manassas  Va  20109

    48

    49                    email:    rob.walter@assett.net"

    50

    51      DESCRIPTION  "Mib for managing Rob's (edna) ~/net-snmp/test3/ specific objects"

    52

    53      ::= { netSnmp 9996 }

    54

    55  -- Note 9996 chosen since ../test3/ROB-TEST3-MIB.txt uses 9997 and is in directory

    56  -- search list, will cause conflict.

    57

    58  --

    59  -- top level structure

    60  -- Everything prefixed with "test4"

    61  --

    62

    63  test4Master                 OBJECT IDENTIFIER ::= { robTest4 1 }

    64  test4Slave                  OBJECT IDENTIFIER ::= { robTest4 2 }

    65

    66  test4MScalar                OBJECT IDENTIFIER ::= { test4Master 1 }

    67  test4MTbl                   OBJECT IDENTIFIER ::= { test4Master 2 }

    68

    69  test4SScalar                OBJECT IDENTIFIER ::= { test4Slave 1 }

    70  test4STbl                   OBJECT IDENTIFIER ::= { test4Slave 2 }

    71

    72  --

    73  -- Master branch has 2 scalars, an integer an a string.

    74  --

    75

    76  test4MstInt OBJECT-TYPE

    77      SYNTAX      Integer32

    78      MAX-ACCESS  read-write

    79      STATUS      current

    80      DESCRIPTION "To allow verification of master only branch access."

    81      DEFVAL { 7 }

    82      ::= { test4MScalar 1 }

    83

    84  test4MstTable OBJECT-TYPE

    85      SYNTAX      SEQUENCE OF Test4MstTEntry

    86      MAX-ACCESS  not-accessible

    87      STATUS      current

    88      DESCRIPTION

    89          "This table holds an array of 256 integer values"

    90      ::= { test4MTbl 1 }

    91

    92  test4MstTEntry OBJECT-TYPE

    93      SYNTAX      Test4MstTEntry

    94      MAX-ACCESS  not-accessible

    95      STATUS      current

    96      DESCRIPTION

    97          "A row of one integer."

    98      INDEX   { test4MtIndex }

    99      ::= {test4MstTable 1 }

   100

   101  Test4MstTEntry ::= SEQUENCE {

   102      test4MtIndex        Integer32,

   103      test4MtValue        Integer32

   104  }

   105

   106  test4MtIndex    OBJECT-TYPE

   107      SYNTAX      Integer32(1..256)

   108      MAX-ACCESS  not-accessible

   109      STATUS      current

   110      DESCRIPTION

   111          "Identifies the integer to be handled."

   112      ::= { test4MstTEntry 1 }

   113

   114  test4MtValue OBJECT-TYPE

   115      SYNTAX      Integer32

   116      MAX-ACCESS  read-write

   117      STATUS      current

   118      DESCRIPTION

   119          "Hold an integer value."

   120      DEFVAL { 0 }

   121      ::= { test4MstTEntry 2 }

   122

   123  --

   124  -- Slave branch has 2 scalars, an integer an a string.

   125  --

   126

   127  test4SlvInt OBJECT-TYPE

   128      SYNTAX      Integer32

   129      MAX-ACCESS  read-write

   130      STATUS      current

   131      DESCRIPTION "To allow verification of slave only branch access."

   132      DEFVAL { 21 }

   133      ::= { test4SScalar 1 }

   134

   135  test4SlvTable OBJECT-TYPE

   136      SYNTAX      SEQUENCE OF Test4SlvTEntry

   137      MAX-ACCESS  not-accessible

   138      STATUS      current

   139      DESCRIPTION

   140          "This table holds an array of 256 integer values"

   141      ::= { test4STbl 1 }

   142

   143  test4SlvTEntry OBJECT-TYPE

   144      SYNTAX      Test4SlvTEntry

   145      MAX-ACCESS  not-accessible

   146      STATUS      current

   147      DESCRIPTION

   148          "A row of one integer."

   149      INDEX   { test4StIndex }

   150      ::= {test4SlvTable 1 }

   151

   152  Test4SlvTEntry ::= SEQUENCE {

   153      test4StIndex        Integer32,

   154      test4StValue        Integer32

   155  }

   156

   157  test4StIndex    OBJECT-TYPE

   158      SYNTAX      Integer32(1..256)

   159      MAX-ACCESS  not-accessible

   160      STATUS      current

   161      DESCRIPTION

   162          "Identifies the integer to be handled."

   163      ::= { test4SlvTEntry 1 }

   164

   165  test4STvalue OBJECT-TYPE

   166      SYNTAX      Integer32

   167      MAX-ACCESS  read-write

   168      STATUS      current

   169      DESCRIPTION

   170          "Hold an integer value."

   171      DEFVAL { 0 }

   172      ::= { test4SlvTEntry 2 }

   173

   174  -- END:  Don't forget this!

   175  END

 

 

[Rob edna:~/net-snmp/test4/test-c] $ snmptranslate -Tp -IR robTest4

+--robTest4(9996)

   |

   +--test4Master(1)

   |  |

   |  +--test4MScalar(1)

   |  |  |

   |  |  +-- -RW- Integer32 test4MstInt(1)

   |  |

   |  +--test4MTbl(2)

   |     |

   |     +--test4MstTable(1)

   |        |

   |        +--test4MstTEntry(1)

   |           |  Index: test4MtIndex

   |           |

   |           +-- ---- Integer32 test4MtIndex(1)

   |           |        Range: 1..256

   |           +-- -RW- Integer32 test4MtValue(2)

   |

   +--test4Slave(2)

      |

      +--test4SScalar(1)

      |  |

      |  +-- -RW- Integer32 test4SlvInt(1)

      |

      +--test4STbl(2)

         |

         +--test4SlvTable(1)

            |

            +--test4SlvTEntry(1)

               |  Index: test4StIndex

               |

               +-- ---- Integer32 test4StIndex(1)

               |        Range: 1..256

               +-- -RW- Integer32 test4STvalue(2)

[Rob edna:~/net-snmp/test4/test-c] $

 

 

 

***PIECE #2: the 3 files generated

----------------------------------

 

  We have 3 files, the beginning of each tagged with its name enclosed within

  << >>:

 

   1) test4Master_subagent.c (218 lines)

 

   2) test4MstTable.h (121 lines)

 

   3) test4MstTable.c (870 lines - sorry about the volume)

 

<<test4Master_subagent.c>>

--------------------------

 

 

     1  /*

     2   * Note: this file originally auto-generated by mbi2c using

     3   *       version : 1.7 $ of : subagent.m2c,v $

     4   */

     5  /*

     6   * standard Net-SNMP includes

     7   */

     8  #include <net-snmp/net-snmp-config.h>

     9  #include <net-snmp/net-snmp-includes.h>

    10  #include <net-snmp/agent/net-snmp-agent-includes.h>

    11

    12  /*

    13   * include our parent header

    14   */

    15  // 05/04/2007 hmmm, mib2c gen'd inappropriate include?

    16  //#include "test4Master.h"

    17  #include "test4MstTable.h"

    18

    19  // 05/04/07 This always seems to be needed.

    20  void            netsnmp_enable_subagent(void);

    21

    22  #include <signal.h>

    23

    24  static int      keep_running;

    25

    26  static          RETSIGTYPE

    27  stop_server(int a)

    28  {

    29      keep_running = 0;

    30  }

    31

    32  static void

    33  usage(void)

    34  {

    35      printf

    36          ("usage: test4Master [-D<tokens>] [-f] [-L] [-M] [-H] [LISTENING ADDRESSES]\n"

    37           "\t-f      Do not fork() from the calling shell.\n"

    38           "\t-DTOKEN[,TOKEN,...]\n"

    39           "\t\tTurn on debugging output for the given TOKEN(s).\n"

    40           "\t\tWithout any tokens specified, it defaults to printing\n"

    41           "\t\tall the tokens (which is equivalent to the keyword 'ALL').\n"

    42           "\t\tYou might want to try ALL for extremely verbose output.\n"

    43           "\t\tNote: You can't put a space between the -D and the TOKENs.\n"

    44           "\t-H\tDisplay a list of configuration file directives\n"

    45           "\t\tunderstood by the agent and then exit.\n"

    46           "\t-M\tRun as a normal SNMP Agent instead of an AgentX sub-agent.\n"

    47           "\t-x ADDRESS\tconnect to master agent at ADDRESS (default /var/agentx/master).\n"

    48           "\t-L\tDo not open a log file; print all messages to stderr.\n");

    49      exit(0);

    50  }

    51

    52  int

    53  main(int argc, char **argv)

    54  {

    55      int             agentx_subagent = 1;        /* change this if you want to be a SNMP master agent */

    56      /*

    57       * Defs for arg-handling code: handles setting of policy-related variables

    58       */

    59      int             ch;

    60      extern char    *optarg;

    61      int             dont_fork = 0, use_syslog = 0;

    62      char           *agentx_socket = NULL;

    63

    64      while ((ch = getopt(argc, argv, "D:fHLMx:")) != EOF)

    65          switch (ch) {

    66          case 'D':

    67              debug_register_tokens(optarg);

    68              snmp_set_do_debugging(1);

    69              break;

    70          case 'f':

    71              dont_fork = 1;

    72              break;

    73          case 'H':

    74

    75              // 05/07/07 I should never hit this, so ignore.

    76              printf ("\n H argv - should not see this!\n");

    77              netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,

    78                                     NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);

    79              init_agent("test4Master");  /* register our .conf handlers */

    80

    81              // init_test4Master();

    82              init_test4MstTable();  // replace original call to "init_test4Master()"

    83

    84              init_snmp("test4Master");

    85              fprintf(stderr, "Configuration directives understood:\n");

    86              read_config_print_usage("  ");

    87              exit(0);

    88          case 'M':

    89              agentx_subagent = 0;

    90              break;

    91          case 'L':

    92              use_syslog = 0;     /* use stderr */

    93              break;

    94          case 'x':

    95              agentx_socket = optarg;

    96              break;

    97          default:

    98              fprintf(stderr, "unknown option %c\n", ch);

    99              usage();

   100          }

   101

   102      if (optind < argc) {

   103          int             i;

   104          /*

   105           * There are optional transport addresses on the command line.

   106           */

   107          DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));

   108          for (i = optind; i < argc; i++) {

   109              char           *c, *astring;

   110              if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,

   111                                             NETSNMP_DS_AGENT_PORTS))) {

   112                  astring = malloc(strlen(c) + 2 + strlen(argv[i]));

   113                  if (astring == NULL) {

   114                      fprintf(stderr, "malloc failure processing argv[%d]\n",

   115                              i);

   116                      exit(1);

   117                  }

   118                  sprintf(astring, "%s,%s", c, argv[i]);

   119                  netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,

   120                                        NETSNMP_DS_AGENT_PORTS, astring);

   121                  SNMP_FREE(astring);

   122              } else {

   123                  netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,

   124                                        NETSNMP_DS_AGENT_PORTS, argv[i]);

   125              }

   126          }

   127          DEBUGMSGTL(("snmpd/main", "port spec: %s\n",

   128                      netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,

   129                                            NETSNMP_DS_AGENT_PORTS)));

   130      }

   131

   132      /*

   133       * we're an agentx subagent?

   134       */

   135      if (agentx_subagent) {

   136          /*

   137           * make us a agentx client.

   138           */

   139          netsnmp_enable_subagent();

   140          if (NULL != agentx_socket)

   141              netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,

   142                                    NETSNMP_DS_AGENT_X_SOCKET,

   143                                    agentx_socket);

   144      }

   145

   146      snmp_disable_log();

   147      if (use_syslog)

   148          snmp_enable_calllog();

   149      else

   150          snmp_enable_stderrlog();

   151

   152      /*

   153       * daemonize

   154       */

   155      if (!dont_fork) {

   156          int             rc = netsnmp_daemonize(1, !use_syslog);

   157          if (rc)

   158              exit(-1);

   159      }

   160

   161      /*

   162       * initialize tcp/ip if necessary

   163       */

   164      SOCK_STARTUP;

   165

   166      /*

   167       * initialize the agent library

   168       */

   169      // init_agent("test4Master");

   170      init_agent("test4MstTable");  // 05/07/07 RJW wild guess.

   171

   172      /*

   173       * init test4Master mib code

   174       */

   175      // init_test4Master();

   176      init_test4MstTable();  // replace original call to "init_test4Master()"

   177

   178      /*

   179       * read test4Master.conf files.

   180       */

   181      // init_snmp("test4Master");

   182      init_snmp("test4MstTable");   // 05/07/07 RJW wild guess.

   183

   184      /*

   185       * If we're going to be a snmp master agent, initial the ports

   186       */

   187      if (!agentx_subagent)

   188          init_master_agent();    /* open the port to listen on (defaults to udp:161) */

   189

   190      /*

   191       * In case we recevie a request to stop (kill -TERM or kill -INT)

   192       */

   193      keep_running = 1;

   194      signal(SIGTERM, stop_server);

   195      signal(SIGINT, stop_server);

   196

   197      /*

   198       * you're main loop here...

   199       */

   200      while (keep_running) {

   201          /*

   202           * if you use select(), see snmp_select_info() in snmp_api(3)

   203           */

   204          /*

   205           * --- OR ---

   206           */

   207          agent_check_and_process(1);     /* 0 == don't block */

   208      }

   209

   210      /*

   211       * at shutdown time

   212       */

   213      // snmp_shutdown("test4Master");

   214      snmp_shutdown("test4MstTable");   // 05/07/07 RJW wild guess.

   215

   216      SOCK_CLEANUP;

   217      exit(0);

   218  }

 

 

 

<<test4MstTable.h>>

-------------------

 

 

     1

     2

     3  /*

     4   * Note: this file originally auto-generated by mib2c using

     5   *        : mib2c.array-user.conf,v 5.26 2005/04/26 22:13:28 rstory Exp $

     6   *

     7   * $Id:$

     8   *

     9   * Yes, there is lots of code here that you might not use. But it is much

    10   * easier to remove code than to add it!

    11   */

    12  #ifndef TEST4MSTTABLE_H

    13  #define TEST4MSTTABLE_H

    14

    15  #ifdef __cplusplus

    16  extern          "C" {

    17  #endif

    18

    19

    20  #include <net-snmp/net-snmp-config.h>

    21  #include <net-snmp/library/container.h>

    22  #include <net-snmp/agent/table_array.h>

    23

    24          /** Index test4MtIndex is internal */

    25

    26      typedef struct test4MstTable_context_s {

    27          netsnmp_index   index;

    28                           /** THIS MUST BE FIRST!!! */

    29

    30      /*************************************************************

    31       * You can store data internally in this structure.

    32       *

    33       * TODO: You will probably have to fix a few types here...

    34       */

    35          /** INTEGER32 = ASN_INTEGER */

    36          long            test4MtIndex;

    37

    38          /** INTEGER32 = ASN_INTEGER */

    39          long            test4MtValue;

    40

    41

    42          /*

    43           * OR

    44           *

    45           * Keep a pointer to your data

    46           */

    47          void           *data;

    48

    49          /*

    50           *add anything else you want here

    51           */

    52

    53      } test4MstTable_context;

    54

    55  /*************************************************************

    56   * function declarations

    57   */

    58      void            init_test4MstTable(void);

    59      void            initialize_table_test4MstTable(void);

    60      const test4MstTable_context *test4MstTable_get_by_idx(netsnmp_index *);

    61      const test4MstTable_context *test4MstTable_get_by_idx_rs(netsnmp_index

    62                                                               *,

    63                                                               int

    64                                                               row_status);

    65      int             test4MstTable_get_value(netsnmp_request_info *,

    66                                              netsnmp_index *,

    67                                              netsnmp_table_request_info *);

    68

    69

    70  /*************************************************************

    71   * oid declarations

    72   */

    73      extern oid      test4MstTable_oid[];

    74      extern size_t   test4MstTable_oid_len;

    75

    76  #define test4MstTable_TABLE_OID 1,3,6,1,4,1,8072,9996,1,2,1

    77

    78  /*************************************************************

    79   * column number definitions for table test4MstTable

    80   */

    81  #define COLUMN_TEST4MTINDEX 1

    82  #define COLUMN_TEST4MTVALUE 2

    83  #define test4MstTable_COL_MIN 2

    84  #define test4MstTable_COL_MAX 2

    85

    86      /*

    87       * comment out the following line if you don't want a custom sort

    88       */

    89  // 05/07/2007 RJW no custom sort code.

    90  //#define test4MstTable_CUSTOM_SORT

    91

    92      int             test4MstTable_extract_index(test4MstTable_context *

    93                                                  ctx, netsnmp_index * hdr);

    94

    95      void            test4MstTable_set_reserve1(netsnmp_request_group *);

    96      void            test4MstTable_set_reserve2(netsnmp_request_group *);

    97      void            test4MstTable_set_action(netsnmp_request_group *);

    98      void            test4MstTable_set_commit(netsnmp_request_group *);

    99      void            test4MstTable_set_free(netsnmp_request_group *);

   100      void            test4MstTable_set_undo(netsnmp_request_group *);

   101

   102      test4MstTable_context

   103          *test4MstTable_duplicate_row(test4MstTable_context *);

   104      netsnmp_index  *test4MstTable_delete_row(test4MstTable_context *);

   105

   106      int             test4MstTable_can_delete(test4MstTable_context *

   107                                               undo_ctx,

   108                                               test4MstTable_context *

   109                                               row_ctx,

   110                                               netsnmp_request_group * rg);

   111

   112

   113

   114  #ifdef test4MstTable_CUSTOM_SORT

   115      test4MstTable_context *test4MstTable_get(const char *name, int len);

   116  #endif

   117

   118  #ifdef __cplusplus

   119  }

   120  #endif

   121  #endif /** TEST4MSTTABLE_H */

 

 

 

<<test4MstTable.c >>

--------------------

 

     1  /*

     2   * Note: this file originally auto-generated by mib2c using

     3   *       : mib2c.array-user.conf,v 5.26 2005/04/26 22:13:28 rstory Exp $

     4   *

     5   * $Id:$

     6   *

     7   *

     8   * For help understanding NET-SNMP in general, please check the

     9   *     documentation and FAQ at:

    10   *

    11   *     http://www.net-snmp.org/

    12   *

    13   *

    14   * For help understanding this code, the agent and how it processes

    15   *     requests, please check the following references.

    16   *

    17   *     http://www.net-snmp.org/tutorial-5/

    18   *

    19   *

    20   * You can also join the #net-snmp channel on irc.freenode.net

    21   *     and ask for help there.

    22   *

    23   *

    24   * And if all else fails, send a detailed message to the developers

    25   *     describing the problem you are having to:

    26   *

    27   *    net-snmp-coders@lists.sourceforge.net

    28   *

    29   *

    30   * Yes, there is lots of code here that you might not use. But it is much

    31   * easier to remove code than to add it!

    32   */

    33  #include <net-snmp/net-snmp-config.h>

    34  #include <net-snmp/net-snmp-includes.h>

    35  #include <net-snmp/agent/net-snmp-agent-includes.h>

    36

    37  #include <net-snmp/library/snmp_assert.h>

    38

    39  #include "test4MstTable.h"

    40

    41  static netsnmp_handler_registration *my_handler = NULL;

    42  static netsnmp_table_array_callbacks cb;

    43

    44  oid             test4MstTable_oid[] = { test4MstTable_TABLE_OID };

    45  size_t          test4MstTable_oid_len = OID_LENGTH(test4MstTable_oid);

    46

    47  // 05/07/07 RJW: guessing that these are effectively row items, and

    48  //               I need 256 of them. Good luck.

    49  static test4MstTable_context mst4_tbl_array[256];

    50

    51

    52  #ifdef test4MstTable_CUSTOM_SORT

    53  /************************************************************

    54   * keep binary tree to find context by name

    55   */

    56  static int      test4MstTable_cmp(const void *lhs, const void *rhs);

    57

    58  /************************************************************

    59   * compare two context pointers here. Return -1 if lhs < rhs,

    60   * 0 if lhs == rhs, and 1 if lhs > rhs.

    61   */

    62  static int

    63  test4MstTable_cmp(const void *lhs, const void *rhs)

    64  {

    65      test4MstTable_context *context_l = (test4MstTable_context *) lhs;

    66      test4MstTable_context *context_r = (test4MstTable_context *) rhs;

    67

    68      // RJW: diagnostic

    69      printf ("\nEntering test4MstTable_cmp().\n");

    70

    71      /*

    72       * check primary key, then secondary. Add your own code if

    73       * there are more than 2 keys

    74       */

    75      int             rc;

    76

    77      /*

    78       * TODO: implement compare. Remove this ifdef code and

    79       * add your own code here.

    80       */

    81  #ifdef TABLE_CONTAINER_TODO

    82      snmp_log(LOG_ERR,

    83               "test4MstTable_compare not implemented! Container order undefined\n");

    84      return 0;

    85  #endif

    86

    87      /*

    88       * EXAMPLE (assuming you want to sort on a name):

    89       *

    90       * rc = strcmp( context_l->xxName, context_r->xxName );

    91       *

    92       * if(rc)

    93       *   return rc;

    94       *

    95       * TODO: fix secondary keys (or delete if there are none)

    96       *

    97       * if(context_l->yy < context_r->yy)

    98       *   return -1;

    99       *

   100       * return (context_l->yy == context_r->yy) ? 0 : 1;

   101       */

   102  }

   103

   104  /************************************************************

   105   * search tree

   106   */

   107  /** TODO: set additional indexes as parameters */

   108  test4MstTable_context *

   109  test4MstTable_get(const char *name, int len)

   110  {

   111      test4MstTable_context tmp;

   112

   113      // RJW: Diagnostic

   114      printf ("\nEntering test4MstTable_get(), should never see this.\n");

   115

   116      /** we should have a custom container */

   117      netsnmp_assert(cb.container->next != NULL);

   118

   119      /*

   120       * TODO: implement compare. Remove this ifdef code and

   121       * add your own code here.

   122       */

   123  #ifdef TABLE_CONTAINER_TODO

   124      snmp_log(LOG_ERR, "test4MstTable_get not implemented!\n");

   125      return NULL;

   126  #endif

   127

   128      /*

   129       * EXAMPLE:

   130       *

   131       * if(len > sizeof(tmp.xxName))

   132       *   return NULL;

   133       *

   134       * strncpy( tmp.xxName, name, sizeof(tmp.xxName) );

   135       * tmp.xxName_len = len;

   136       *

   137       * return CONTAINER_FIND(cb.container->next, &tmp);

   138       */

   139  }

   140  #endif

   141

   142

   143  /************************************************************

   144   * Initializes the test4MstTable module

   145   */

   146  void

   147  init_test4MstTable(void)

   148  {

   149     // RJW: debug stuff, recall this copied from the netsnmp library

   150     //      container_binary_array.c

   151  typedef struct binary_array_table_s {

   152      size_t                     max_size;   /* Size of the current data table */

   153      size_t                     count;      /* Index of the next free entry */

   154      u_int                      flags;      /* flags */

   155      int                        dirty;

   156      int                        data_size;  /* Size of an individual entry */

   157      void                     **data;       /* The table itself */

   158  } binary_array_table;

   159

   160     // 05/07/07 RJW: will need this below

   161     test4MstTable_context * new_row;

   162     int i;

   163     oid my_oid[4];

   164

   165     // RJW: debug support

   166     binary_array_table *t;

   167

   168      initialize_table_test4MstTable();

   169

   170      /*

   171       * TODO: perform any startup stuff here, such as

   172       * populating the table with initial data.

   173       *

   174       * test4MstTable_context * new_row = create_row(index);

   175       * CONTAINER_INSERT(cb.container,new_row);

   176       */

   177

   178     // 05/07/07 RJW let's try to set the offending flag. Wonder what this

   179     //          "duplicate stuff" is all about...

   180     t = (binary_array_table*)((cb.container)->container_data);

   181     t->flags |= CONTAINER_KEY_ALLOW_DUPLICATES;

   182

   183     // 05/07/07 RJW: well, test is for 256 table rows of one integer each

   184     for (i=1; i<257; i++)

   185     {

   186        // 05/04/07 this "new_row = create_row(i)" is somewhat misleading, I need

   187        //          to implement it in fact, using mst4_tbl_array[256] as a first

   188        //          guess since I thought mallocs were bothersome.

   189        my_oid[0] = i;

   190        mst4_tbl_array[i-1].index.oids = my_oid;

   191        mst4_tbl_array[i-1].index.len = 1;

   192        mst4_tbl_array[i-1].test4MtIndex = i;

   193        mst4_tbl_array[i-1].test4MtValue = i;  // possible verify init val, tho recall mib says 0

   194        new_row = &mst4_tbl_array[i-1];

   195        CONTAINER_INSERT(cb.container,new_row);

   196     }

   197

   198  }

   199

   200  /************************************************************

   201   * the *_row_copy routine

   202   */

   203  static int

   204  test4MstTable_row_copy(test4MstTable_context * dst,

   205                         test4MstTable_context * src)

   206  {

   207

   208    // 05/07/07 RJW investigatory.

   209    printf ("\n Enter test4MstTable_row_copy()\n");

   210

   211      if (!dst || !src)

   212          return 1;

   213

   214      /*

   215       * copy index, if provided

   216       */

   217      if (dst->index.oids)

   218          free(dst->index.oids);

   219      if (snmp_clone_mem((void *) &dst->index.oids, src->index.oids,

   220                         src->index.len * sizeof(oid))) {

   221          dst->index.oids = NULL;

   222          return 1;

   223      }

   224      dst->index.len = src->index.len;

   225

   226

   227      /*

   228       * copy components into the context structure

   229       */

   230      dst->test4MtIndex = src->test4MtIndex;

   231

   232      dst->test4MtValue = src->test4MtValue;

   233

   234    // 05/07/07 RJW investigatory.

   235    printf ("\n Clean exit test4MstTable_row_copy()\n");

   236

   237      return 0;

   238  }

   239

   240  /**

   241   * the *_extract_index routine

   242   *

   243   * This routine is called when a set request is received for an index

   244   * that was not found in the table container. Here, we parse the oid

   245   * in the the individual index components and copy those indexes to the

   246   * context. Then we make sure the indexes for the new row are valid.

   247   */

   248  int

   249  test4MstTable_extract_index(test4MstTable_context * ctx,

   250                              netsnmp_index * hdr)

   251  {

   252      /*

   253       * temporary local storage for extracting oid index

   254       *

   255       * extract index uses varbinds (netsnmp_variable_list) to parse

   256       * the index OID into the individual components for each index part.

   257       */

   258      netsnmp_variable_list var_test4MtIndex;

   259      int             err;

   260

   261      // RJW: Diagnostic

   262      printf ("\nEnter test4MstTable_extract_index().\n");

   263

   264      /*

   265       * copy index, if provided

   266       */

   267      if (hdr) {

   268          netsnmp_assert(ctx->index.oids == NULL);

   269          if ((hdr->len > MAX_OID_LEN) ||

   270              snmp_clone_mem((void *) &ctx->index.oids, hdr->oids,

   271                             hdr->len * sizeof(oid))) {

   272              return -1;

   273          }

   274          ctx->index.len = hdr->len;

   275      }

   276

   277      /*

   278       * initialize variable that will hold each component of the index.

   279       * If there are multiple indexes for the table, the variable_lists

   280       * need to be linked together, in order.

   281       */

   282      memset(&var_test4MtIndex, 0x00, sizeof(var_test4MtIndex));

   283      var_test4MtIndex.type = ASN_INTEGER;        /* type hint for parse_oid_indexes */

   284         /** TODO: link this index to the next, or NULL for the last one */

   285  #ifdef TABLE_CONTAINER_TODO

   286      snmp_log(LOG_ERR,

   287               "test4MstTable_extract_index index list not implemented!\n");

   288      return 0;

   289  #else

   290      // 05/04/07 RJW: Conserned about this since I have it pointing to itself, but

   291      //          don't expect this code to execute.

   292      // var_test4MTindex.next_variable = &var_XX;

   293

   294      printf ("\n No idea how to set this, test4MstTable_extract_index().\n");

   295      var_test4MtIndex.next_variable = &var_test4MtIndex;

   296  #endif

   297

   298

   299      /*

   300       * parse the oid into the individual index components

   301       */

   302      err = parse_oid_indexes(hdr->oids, hdr->len, &var_test4MtIndex);

   303      if (err == SNMP_ERR_NOERROR) {

   304          /*

   305           * copy index components into the context structure

   306           */

   307          ctx->test4MtIndex = *var_test4MtIndex.val.integer;

   308

   309

   310          /*

   311           * TODO: check index for valid values. For EXAMPLE:

   312           *

   313           * if ( *var_test4MtIndex.val.integer != XXX ) {

   314           *    err = -1;

   315           * }

   316           */

   317      }

   318

   319      /*

   320       * parsing may have allocated memory. free it.

   321       */

   322      snmp_reset_var_buffers(&var_test4MtIndex);

   323

   324      return err;

   325  }

   326

   327  /************************************************************

   328   * the *_can_delete routine is called to determine if a row

   329   * can be deleted.

   330   *

   331   * return 1 if the row can be deleted

   332   * return 0 if the row cannot be deleted

   333   */

   334  int

   335  test4MstTable_can_delete(test4MstTable_context * undo_ctx,

   336                           test4MstTable_context * row_ctx,

   337                           netsnmp_request_group * rg)

   338  {

   339

   340      /*

   341       * TODO: check for other deletion requirements here

   342       */

   343      return 1;

   344  }

   345

   346

   347  /************************************************************

   348   * the *_duplicate row routine

   349   */

   350  test4MstTable_context *

   351  test4MstTable_duplicate_row(test4MstTable_context * row_ctx)

   352  {

   353      test4MstTable_context *dup;

   354

   355    // 05/07/07 RJW investigatory.

   356    printf ("\n Enter t4MstTable_duplicate_row)\n");

   357

   358      if (!row_ctx)

   359          return NULL;

   360

   361      dup = SNMP_MALLOC_TYPEDEF(test4MstTable_context);

   362      if (!dup)

   363          return NULL;

   364

   365      if (test4MstTable_row_copy(dup, row_ctx)) {

   366          free(dup);

   367          dup = NULL;

   368      }

   369

   370    // 05/07/07 RJW investigatory.

   371    printf ("\n Clean exit t4MstTable_duplicate_row)\n");

   372

   373      return dup;

   374  }

   375

   376  /************************************************************

   377   * the *_delete_row method is called to delete a row.

   378   */

   379  netsnmp_index  *

   380  test4MstTable_delete_row(test4MstTable_context * ctx)

   381  {

   382      /*

   383       * netsnmp_mutex_destroy(ctx->lock);

   384       */

   385

   386      if (ctx->index.oids)

   387          free(ctx->index.oids);

   388

   389      /*

   390       * TODO: release any memory you allocated here...

   391       */

   392

   393      /*

   394       * release header

   395       */

   396      free(ctx);

   397

   398      return NULL;

   399  }

   400

   401

   402  /************************************************************

   403   * RESERVE is used to check the syntax of all the variables

   404   * provided, that the values being set are sensible and consistent,

   405   * and to allocate any resources required for performing the SET.

   406   * After this stage, the expectation is that the set ought to

   407   * succeed, though this is not guaranteed. (In fact, with the UCD

   408   * agent, this is done in two passes - RESERVE1, and

   409   * RESERVE2, to allow for dependancies between variables).

   410   *

   411   * BEFORE calling this routine, the agent will call duplicate_row

   412   * to create a copy of the row (unless this is a new row; i.e.

   413   * row_created == 1).

   414   *

   415   * next state -> SET_RESERVE2 || SET_FREE

   416   */

   417  void

   418  test4MstTable_set_reserve1(netsnmp_request_group * rg)

   419  {

   420      test4MstTable_context *row_ctx =

   421          (test4MstTable_context *) rg->existing_row;

   422

   423      // 05/07/07 RJW: make complains "unused..."

   424      // test4MstTable_context *undo_ctx =

   425      //     (test4MstTable_context *) rg->undo_info;

   426      netsnmp_variable_list *var;

   427      netsnmp_request_group_item *current;

   428      int             rc;

   429

   430

   431      /*

   432       * TODO: loop through columns, check syntax and lengths. For

   433       * columns which have no dependencies, you could also move

   434       * the value/range checking here to attempt to catch error

   435       * cases as early as possible.

   436       */

   437      for (current = rg->list; current; current = current->next) {

   438

   439          var = current->ri->requestvb;

   440          rc = SNMP_ERR_NOERROR;

   441

   442          switch (current->tri->colnum) {

   443

   444          case COLUMN_TEST4MTVALUE:

   445              /** INTEGER32 = ASN_INTEGER */

   446              rc = netsnmp_check_vb_type_and_size(var, ASN_INTEGER,

   447                                                  sizeof(row_ctx->

   448                                                         test4MtValue));

   449              break;

   450

   451          default:/** We shouldn't get here */

   452              rc = SNMP_ERR_GENERR;

   453              snmp_log(LOG_ERR, "unknown column in "

   454                       "test4MstTable_set_reserve1\n");

   455          }

   456

   457          if (rc)

   458              netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri,

   459                                             rc);

   460          rg->status = SNMP_MAX(rg->status, current->ri->status);

   461      }

   462

   463      /*

   464       * done with all the columns. Could check row related

   465       * requirements here.

   466       */

   467  }

   468

   469  void

   470  test4MstTable_set_reserve2(netsnmp_request_group * rg)

   471  {

   472      // 05/07/07 RJW: make complains "unused..."

   473      // test4MstTable_context *row_ctx =

   474      //     (test4MstTable_context *) rg->existing_row;

   475      // test4MstTable_context *undo_ctx =

   476      //     (test4MstTable_context *) rg->undo_info;

   477

   478      netsnmp_request_group_item *current;

   479      netsnmp_variable_list *var;

   480      int             rc;

   481

   482      rg->rg_void = rg->list->ri;

   483

   484      /*

   485       * TODO: loop through columns, check for valid

   486       * values and any range constraints.

   487       */

   488      for (current = rg->list; current; current = current->next) {

   489

   490          var = current->ri->requestvb;

   491          rc = SNMP_ERR_NOERROR;

   492

   493          switch (current->tri->colnum) {

   494

   495          case COLUMN_TEST4MTVALUE:

   496              /** INTEGER32 = ASN_INTEGER */

   497              /*

   498               * TODO: routine to check valid values

   499               *

   500               * EXAMPLE:

   501               *

   502               * if ( *var->val.integer != XXX ) {

   503               *    rc = SNMP_ERR_INCONSISTENTVALUE;

   504               *    rc = SNMP_ERR_BADVALUE;

   505               * }

   506               */

   507              break;

   508

   509          default:/** We shouldn't get here */

   510              netsnmp_assert(0); /** why wasn't this caught in reserve1? */

   511          }

   512

   513          if (rc)

   514              netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri,

   515                                             rc);

   516      }

   517

   518      /*

   519       * done with all the columns. Could check row related

   520       * requirements here.

   521       */

   522  }

   523

   524  /************************************************************

   525   * Assuming that the RESERVE phases were successful, the next

   526   * stage is indicated by the action value ACTION. This is used

   527   * to actually implement the set operation. However, this must

   528   * either be done into temporary (persistent) storage, or the

   529   * previous value stored similarly, in case any of the subsequent

   530   * ACTION calls fail.

   531   *

   532   * In your case, changes should be made to row_ctx. A copy of

   533   * the original row is in undo_ctx.

   534   */

   535  void

   536  test4MstTable_set_action(netsnmp_request_group * rg)

   537  {

   538      netsnmp_variable_list *var;

   539      test4MstTable_context *row_ctx =

   540          (test4MstTable_context *) rg->existing_row;

   541

   542      // 05/07/07 RJW: make complains "unused..."

   543      // test4MstTable_context *undo_ctx =

   544      //     (test4MstTable_context *) rg->undo_info;

   545      netsnmp_request_group_item *current;

   546

   547      // RJW: Diagnostic

   548      printf ("\nEnter test4MstTable_set_action()\n");

   549

   550      /*

   551       * TODO: loop through columns, copy varbind values

   552       * to context structure for the row.

   553       */

   554      for (current = rg->list; current; current = current->next) {

   555

   556          var = current->ri->requestvb;

   557

   558          switch (current->tri->colnum) {

   559

   560          case COLUMN_TEST4MTVALUE:

   561              /** INTEGER32 = ASN_INTEGER */

   562              row_ctx->test4MtValue = *var->val.integer;

   563              break;

   564

   565          default:/** We shouldn't get here */

   566              netsnmp_assert(0); /** why wasn't this caught in reserve1? */

   567          }

   568      }

   569

   570      /*

   571       * done with all the columns. Could check row related

   572       * requirements here.

   573       */

   574      /*

   575       * TODO: if you have dependencies on other tables, this would be

   576       * a good place to check those, too.

   577       */

   578  }

   579

   580  /************************************************************

   581   * Only once the ACTION phase has completed successfully, can

   582   * the final COMMIT phase be run. This is used to complete any

   583   * writes that were done into temporary storage, and then release

   584   * any allocated resources. Note that all the code in this phase

   585   * should be "safe" code that cannot possibly fail (cue

   586   * hysterical laughter). The whole intent of the ACTION/COMMIT

   587   * division is that all of the fallible code should be done in

   588   * the ACTION phase, so that it can be backed out if necessary.

   589   *

   590   * BEFORE calling this routine, the agent will update the

   591   * container (inserting a row if row_created == 1, or removing

   592   * the row if row_deleted == 1).

   593   *

   594   * AFTER calling this routine, the agent will delete the

   595   * undo_info.

   596   */

   597  void

   598  test4MstTable_set_commit(netsnmp_request_group * rg)

   599  {

   600      netsnmp_variable_list *var;

   601

   602      // 05/04/07 RJW: make complains "unused..."

   603      // test4MstTable_context *row_ctx =

   604      //     (test4MstTable_context *) rg->existing_row;

   605      // test4MstTable_context *undo_ctx =

   606      //     (test4MstTable_context *) rg->undo_info;

   607

   608      netsnmp_request_group_item *current;

   609

   610      /*

   611       * loop through columns

   612       */

   613      for (current = rg->list; current; current = current->next) {

   614

   615          var = current->ri->requestvb;

   616

   617          switch (current->tri->colnum) {

   618

   619          case COLUMN_TEST4MTVALUE:

   620              /** INTEGER32 = ASN_INTEGER */

   621              break;

   622

   623          default:/** We shouldn't get here */

   624              netsnmp_assert(0); /** why wasn't this caught in reserve1? */

   625          }

   626      }

   627

   628      /*

   629       * done with all the columns. Could check row related

   630       * requirements here.

   631       */

   632  }

   633

   634  /************************************************************

   635   * If either of the RESERVE calls fail, the write routines

   636   * are called again with the FREE action, to release any resources

   637   * that have been allocated. The agent will then return a failure

   638   * response to the requesting application.

   639   *

   640   * AFTER calling this routine, the agent will delete undo_info.

   641   */

   642  void

   643  test4MstTable_set_free(netsnmp_request_group * rg)

   644  {

   645      netsnmp_variable_list *var;

   646

   647      // 05/04/07 RJW: make complains row_ctx & undo_ctx unused, comment out.

   648      //  test4MstTable_context *row_ctx =

   649      //      (test4MstTable_context *) rg->existing_row;

   650      //  test4MstTable_context *undo_ctx =

   651      //      (test4MstTable_context *) rg->undo_info;

   652

   653      netsnmp_request_group_item *current;

   654

   655      /*

   656       * loop through columns

   657       */

   658      for (current = rg->list; current; current = current->next) {

   659

   660          var = current->ri->requestvb;

   661

   662          switch (current->tri->colnum) {

   663

   664          case COLUMN_TEST4MTVALUE:

   665              /** INTEGER32 = ASN_INTEGER */

   666              break;

   667

   668          default:/** We shouldn't get here */

   669              /** should have been logged in reserve1 */

   670

   671              // weird, cannot have naked default at end.

   672              break;

   673          }

   674      }

   675

   676      /*

   677       * done with all the columns. Could check row related

   678       * requirements here.

   679       */

   680  }

   681

   682  /************************************************************

   683   * If the ACTION phase does fail (for example due to an apparently

   684   * valid, but unacceptable value, or an unforeseen problem), then

   685   * the list of write routines are called again, with the UNDO

   686   * action. This requires the routine to reset the value that was

   687   * changed to its previous value (assuming it was actually changed),

   688   * and then to release any resources that had been allocated. As

   689   * with the FREE phase, the agent will then return an indication

   690   * of the error to the requesting application.

   691   *

   692   * BEFORE calling this routine, the agent will update the container

   693   * (remove any newly inserted row, re-insert any removed row).

   694   *

   695   * AFTER calling this routing, the agent will call row_copy

   696   * to restore the data in existing_row from the date in undo_info.

   697   * Then undo_info will be deleted (or existing row, if row_created

   698   * == 1).

   699   */

   700  void

   701  test4MstTable_set_undo(netsnmp_request_group * rg)

   702  {

   703      netsnmp_variable_list *var;

   704

   705      // 05/04/07 RJW: make complains row_ctx & undo_ctx unused, so comment out.

   706  //     test4MstTable_context *row_ctx =

   707  //         (test4MstTable_context *) rg->existing_row;

   708  //     test4MstTable_context *undo_ctx =

   709  //         (test4MstTable_context *) rg->undo_info;

   710

   711      netsnmp_request_group_item *current;

   712

   713      /*

   714       * loop through columns

   715       */

   716      for (current = rg->list; current; current = current->next) {

   717

   718          var = current->ri->requestvb;

   719

   720          switch (current->tri->colnum) {

   721

   722          case COLUMN_TEST4MTVALUE:

   723              /** INTEGER32 = ASN_INTEGER */

   724              break;

   725

   726          default:/** We shouldn't get here */

   727              netsnmp_assert(0); /** why wasn't this caught in reserve1? */

   728          }

   729      }

   730

   731      /*

   732       * done with all the columns. Could check row related

   733       * requirements here.

   734       */

   735  }

   736

   737

   738

   739  /************************************************************

   740   *

   741   * Initialize the test4MstTable table by defining its contents and how it's structured

   742   */

   743  void

   744  initialize_table_test4MstTable(void)

   745  {

   746      netsnmp_table_registration_info *table_info;

   747

   748      if (my_handler) {

   749          snmp_log(LOG_ERR,

   750                   "initialize_table_test4MstTable_handler called again\n");

   751          return;

   752      }

   753

   754      memset(&cb, 0x00, sizeof(cb));

   755

   756      /** create the table structure itself */

   757      table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);

   758

   759      my_handler = netsnmp_create_handler_registration("test4MstTable",

   760                                                       netsnmp_table_array_helper_handler,

   761                                                       test4MstTable_oid,

   762                                                       test4MstTable_oid_len,

   763                                                       HANDLER_CAN_RWRITE);

   764

   765      if (!my_handler || !table_info) {

   766          snmp_log(LOG_ERR, "malloc failed in "

   767                   "initialize_table_test4MstTable_handler\n");

   768          return; /** mallocs failed */

   769      }

   770

   771      /***************************************************

   772       * Setting up the table's definition

   773       */

   774      /*

   775       * TODO: add any external indexes here.

   776       */

   777

   778      /*

   779       * internal indexes

   780       */

   781          /** index: test4MtIndex */

   782      netsnmp_table_helper_add_index(table_info, ASN_INTEGER);

   783

   784      table_info->min_column = test4MstTable_COL_MIN;

   785      table_info->max_column = test4MstTable_COL_MAX;

   786

   787      /***************************************************

   788       * registering the table with the master agent

   789       */

   790      cb.get_value = test4MstTable_get_value;

   791      cb.container = netsnmp_container_find("test4MstTable_primary:"

   792                                            "test4MstTable:"

   793                                            "table_container");

   794  #ifdef test4MstTable_CUSTOM_SORT

   795      netsnmp_container_add_index(cb.container,

   796                                  netsnmp_container_find

   797                                  ("test4MstTable_custom:" "test4MstTable:"

   798                                   "table_container"));

   799      cb.container->next->compare = test4MstTable_cmp;

   800  #endif

   801      cb.can_set = 1;

   802      cb.duplicate_row = (UserRowMethod *) test4MstTable_duplicate_row;

   803      cb.delete_row = (UserRowMethod *) test4MstTable_delete_row;

   804      cb.row_copy = (Netsnmp_User_Row_Operation *) test4MstTable_row_copy;

   805

   806      cb.can_delete = (Netsnmp_User_Row_Action *) test4MstTable_can_delete;

   807

   808      cb.set_reserve1 = test4MstTable_set_reserve1;

   809      cb.set_reserve2 = test4MstTable_set_reserve2;

   810      cb.set_action = test4MstTable_set_action;

   811      cb.set_commit = test4MstTable_set_commit;

   812      cb.set_free = test4MstTable_set_free;

   813      cb.set_undo = test4MstTable_set_undo;

   814      DEBUGMSGTL(("initialize_table_test4MstTable",

   815                  "Registering table test4MstTable " "as a table array\n"));

   816      netsnmp_table_container_register(my_handler, table_info, &cb,

   817                                       cb.container, 1);

   818  }

   819

   820  /************************************************************

   821   * test4MstTable_get_value

   822   *

   823   * This routine is called for get requests to copy the data

   824   * from the context to the varbind for the request. If the

   825   * context has been properly maintained, you don't need to

   826   * change in code in this fuction.

   827   */

   828  int

   829  test4MstTable_get_value(netsnmp_request_info *request,

   830                          netsnmp_index * item,

   831                          netsnmp_table_request_info *table_info)

   832  {

   833      netsnmp_variable_list *var = request->requestvb;

   834      test4MstTable_context *context = (test4MstTable_context *) item;

   835

   836      // 05/07/07 RJW temp debug

   837      printf ("\nEnter test4MstTable_get_value().\n");

   838

   839      switch (table_info->colnum) {

   840

   841      case COLUMN_TEST4MTVALUE:

   842              /** INTEGER32 = ASN_INTEGER */

   843          // 05/07/07 RJW: apparently mib2c is out of sync with net-snmp lib, the

   844          //          3rd arg of this should be u_char, not char.

   845          snmp_set_var_typed_value(var, ASN_INTEGER,

   846                                   (u_char *) &context->test4MtValue,

   847                                   sizeof(context->test4MtValue));

   848          break;

   849

   850      default:/** We shouldn't get here */

   851          snmp_log(LOG_ERR, "unknown column in "

   852                   "test4MstTable_get_value\n");

   853          return SNMP_ERR_GENERR;

   854      }

   855

   856      // 05/07/07 RJW temp debug

   857      printf ("\nClean exit test4MstTable_get_value().\n");

   858

   859      return SNMP_ERR_NOERROR;

   860  }

   861

   862  /************************************************************

   863   * test4MstTable_get_by_idx

   864   */

   865  const test4MstTable_context *

   866  test4MstTable_get_by_idx(netsnmp_index * hdr)

   867  {

   868      return (const test4MstTable_context *)

   869          CONTAINER_FIND(cb.container, hdr);

   870  }

[Rob edna:~/net-snmp/test4/test-c] $                                                                           

 

 

 

***PIECE #3: the Makefile

-------------------------

 

 

[Rob edna:~/net-snmp/test4/test-c] $ cat Makefile

#

#  11/22/2006 - from www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile

#

#     Recall "ldd", e.g: $ ldd /usr/sbin/snmpd

#

# Warning: you may need more libraries than are included here on the

# build line.  The agent frequently needs various libraries in order

# to compile pieces of it, but is OS dependent and we can't list all

# the combinations here.  Instead, look at the libraries that were

# used when linking the snmpd master agent and copy those to this

# file.

#

#  05/03/2007 - Adapt to current "test4/test-a" effort.

#

 

CC=gcc

 

OBJS2=test4Master_subagent.o  test4MstTable.o

 

TARGETS=test4Mst

 

CFLAGS=-I. `net-snmp-config --cflags`

BUILDLIBS=`net-snmp-config --libs`

BUILDAGENTLIBS=`net-snmp-config --agent-libs`

 

# shared library flags (assumes gcc)

DLFLAGS=-fPIC -shared

 

all: $(TARGETS)

 

test4Mst: $(OBJS2)

        $(CC) -o test4Mst $(OBJS2)  $(BUILDAGENTLIBS)

 

clean:

        rm $(OBJS2) $(TARGETS)

 

[Rob edna:~/net-snmp/test4/test-c]

 

 

***PIECE #4: the subagent execution and snmp tool results against it

--------------------------------------------------------------------

 

 

[Rob edna:~/net-snmp/test4/test-c] $ ps awwux | grep test4Mst

1066     12927  0.0  0.0   3860   776 pts/7    S+   16:59   0:00 grep test4Mst

[Rob edna:~/net-snmp/test4/test-c] $ su

Password:

edna:/home/rob.walter/net-snmp/test4/test-c # ./test4Mst

edna:/home/rob.walter/net-snmp/test4/test-c # NET-SNMP version 5.3.0.1 AgentX subagent connected

 

edna:/home/rob.walter/net-snmp/test4/test-c # exit

exit

[Rob edna:~/net-snmp/test4/test-c] $ ps awwux | grep test4Mst

root     12950  0.6  0.1  31432  4492 ?        S    16:59   0:00 ./test4Mst

1066     12952  0.0  0.0   3864   776 pts/7    S+   16:59   0:00 grep test4Mst

[Rob edna:~/net-snmp/test4/test-c] $

 

 

 

[Rob edna:~/SW_tests/snmp/net-snmp-5.4] $

[Rob edna:~/SW_tests/snmp/net-snmp-5.4] $ snmpwalk -v 1 -c public localhost test4MstTable

ROB-TEST4-MIB::test4MtValue.0 = INTEGER: 171

ROB-TEST4-MIB::test4MtValue.0 = INTEGER: 44

Error: OID not increasing: ROB-TEST4-MIB::test4MtValue.0

 >= ROB-TEST4-MIB::test4MtValue.0

 

[Rob edna:~/SW_tests/snmp/net-snmp-5.4] $ snmpgetnext -c public -v 1 -Ob localhost test4MstTable.0

ROB-TEST4-MIB::test4MtValue.0 = INTEGER: 171

[Rob edna:~/SW_tests/snmp/net-snmp-5.4] $

 

    The preceding is quite suspicious. Appears to treat the item as if it were

    a scalar. I do not know how to interpret the error "OID not increasing".

    In contrast the following is a truncation of the "well known" ifTable.

 

[Rob edna:~/SW_tests/snmp/net-snmp-5.4] $ snmpwalk -v 1 -c public localhost ifTable

[Rob edna:~/SW_tests/snmp/net-snmp-5.4] $

 

IF-MIB::ifIndex.1 = INTEGER: 1

IF-MIB::ifIndex.2 = INTEGER: 2

IF-MIB::ifIndex.3 = INTEGER: 3

IF-MIB::ifIndex.4 = INTEGER: 4

IF-MIB::ifIndex.5 = INTEGER: 5

IF-MIB::ifIndex.6 = INTEGER: 6

IF-MIB::ifDescr.1 = STRING: lo