Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
BSNMPAGENT(3)		 BSD Library Functions Manual		 BSNMPAGENT(3)

     bsnmpagent, snmp_depop_t, snmp_op_t, tree,	tree_size, snmp_trace,
     snmp_debug, snmp_get, snmp_getnext, snmp_getbulk, snmp_set,
     snmp_make_errresp,	snmp_dep_lookup, snmp_init_context, snmp_dep_commit,
     snmp_dep_rollback,	snmp_dep_finish	-- SNMP	agent library

     Begemot SNMP library (libbsnmp, -lbsnmp)

     #include <asn1.h>
     #include <snmp.h>
     #include <snmpagent.h>

     typedef int
     (*snmp_depop_t)(struct snmp_context *ctx, struct snmp_dependency *dep,
	 enum snmp_depop op);

     typedef int
     (*snmp_op_t)(struct snmp_context *ctx, struct snmp_value *val, u_int len,
	 u_int idx, enum snmp_op op);

     extern struct snmp_node *tree;
     extern u_int tree_size;
     extern u_int snmp_trace;
     extern void (*snmp_debug)(const char *fmt,	...);

     enum snmp_ret
     snmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b,
	 struct	snmp_pdu *resp,	void *data);

     enum snmp_ret
     snmp_getnext(struct snmp_pdu *pdu,	struct asn_buf *resp_b,
	 struct	snmp_pdu *resp,	void *data);

     enum snmp_ret
     snmp_getbulk(struct snmp_pdu *pdu,	struct asn_buf *resp_b,
	 struct	snmp_pdu *resp,	void *data);

     enum snmp_ret
     snmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b,
	 struct	snmp_pdu *resp,	void *data);

     enum snmp_ret
     snmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *req_b,
	 struct	asn_buf	*resp_b);

     struct snmp_dependency *
     snmp_dep_lookup(struct snmp_context *ctx, const struct asn_oid *base,
	 const struct asn_oid *idx, size_t alloc, snmp_depop_t func);

     struct snmp_context *

     snmp_dep_commit(struct snmp_context *ctx);

     snmp_dep_rollback(struct snmp_context *ctx);

     snmp_dep_finish(struct snmp_context *ctx);

     The SNMP library contains routines	to easily build	SNMP agent applica-
     tions that	use SNMP versions 1 or 2.  Note, however, that it may be even
     easier to build an	bsnmpd(1) loadable module, that	handles	the new	MIB
     (see snmpmod(3)).

     Most of the agent routines	operate	on a global array that the describes
     the complete MIB served by	the agent.  This array is held in the two

	   extern struct snmp_node *tree;
	   extern u_int	 tree_size;

     The elements of the array are of type struct snmp_node:

	   typedef int (*snmp_op_t)(struct snmp_context	*, struct snmp_value *,
	       u_int, u_int, enum snmp_op);

	   struct snmp_node {
		   struct asn_oid oid;
		   const char	   *name;	   /* name of the leaf */
		   enum	snmp_node_type type;	   /* type of this node	*/
		   enum	snmp_syntax syntax;
		   snmp_op_t	   op;
		   u_int	   flags;
		   u_int32_t	   index;	   /* index data */
		   void		   *data;	   /* application data */
		   void		   *tree_data;	   /* application data */

     The fields	of this	structure are described	below.

     oid     Base OID of the scalar or table column.

     name    Name of this variable.

     type    Type of this variable.  One of:

		   enum	snmp_node_type {
			   SNMP_NODE_LEAF = 1,

     syntax  The SNMP syntax of	this variable.

     op	     The user supplied handler for this	variable.  The handler is
	     called with the following arguments:

	     ctx  A pointer to the context (see	below).	 NULL.

	     val  The value to be set or retrieved.  For GETNEXT and GETBULK
		  operations the oid in	this value is the current OID.	The
		  function (called in this case	only for table rows) must find
		  the lexically	next existing OID within the same column and
		  set the oid and value	subfields accordingly.	If the table
		  column is exhausted the function must	return
		  SNMP_ERR_NOSUCHNAME.	For all	other operations the oid in
		  val is the oid to fetch or set.

	     len  The length of	the base oid without index.

	     idx  For table columns this is the	index expression from the node
		  (see below).

	     op	  This is the operation	to execute, one	of:

			enum snmp_op {
				SNMP_OP_GET	= 1,

	     The user handler must return an appropriate SNMP v2 error code.
	     If	the original PDU was a version 1 PDU, the error	code is	mapped

     flags   Currently only the	flag SNMP_NODE_CANSET is defined and set for
	     nodes, that can be	written	or created.

     index   This word describes the index for table columns.  Each part of
	     the index takes 4 bits starting at	bit 4.	Bits 0 to 3 hold the
	     number of index parts.  This arrangement allows for tables	with
	     up	to seven indexes.  Each	bit group contains the syntax for the
	     index part.  There	are a number of	macros to help in parsing this

		   #define SNMP_INDEXES_MAX	   7
		   #define SNMP_INDEX_SHIFT	   4
		   #define SNMP_INDEX_MASK 0xf
		   #define SNMP_INDEX_COUNT(V)	   ((V)	& SNMP_INDEX_MASK)
		   #define SNMP_INDEX(V,I) \
			   (((V) >> (((I) + 1) * SNMP_INDEX_SHIFT)) & \

     data    This field	may contain arbitrary data and is not used by the li-

     The easiest way to	construct the node table is gensnmptree(1).  Note,
     that one must be careful when changing the	tree while executing a SET op-
     eration.  Consult the sources for bsnmpd(1).

     The global	variable snmp_trace together with the function pointed to by
     snmp_debug	help in	debugging the library and the agent.  snmp_trace is a
     bit mask with the following bits:

	   enum	{

     Setting a bit to true causes the library to call snmp_debug() in strate-
     gic places	with a debug string.  The library contains a default implemen-
     tation for	the debug function that	prints a message to standard error.

     Many of the functions use a so called context:

	   struct snmp_context {
		   u_int   var_index;
		   struct snmp_scratch *scratch;
		   struct snmp_dependency *dep;
		   void	   *data;	   /* user data	*/
		   enum	snmp_ret code;	   /* return code */

	   struct snmp_scratch {
		   void		   *ptr1;
		   void		   *ptr2;
		   uint32_t	   int1;
		   uint32_t	   int2;

     The fields	are used as follows:

     va_index	For the	node operation callback	this is	the index of the vari-
		able binding that should be returned if	an error occurs.  Set
		by the library.	 In all	other functions	this is	undefined.

     scratch	For the	node operation callback	this is	a pointer to a per
		variable binding scratch area that can be used to implement
		the commit and rollback.  Set by the library.

     dep	In the dependency callback function (see below)	this is	a
		pointer	to the current dependency.  Set	by the library.

     data	This is	the data argument from the call	to the library and is
		not used by the	library.

     The next three functions execute different	kinds of GET requests.	The
     function snmp_get() executes an SNMP GET operation, the function
     snmp_getnext() executes an	SNMP GETNEXT operation and the function
     snmp_getbulk() executes an	SNMP GETBULK operation.	 For all three func-
     tions the response	PDU is constructed and encoded on the fly.  If every-
     thing is ok, the response PDU is returned in resp and resp_b.  The	caller
     must call snmp_pdu_free() to free the response PDU	in this	case.  One of
     the following values may be returned:

     SNMP_RET_OK   Operation successful, response PDU may be sent.

     SNMP_RET_IGN  Operation failed, no	response PDU constructed.  Request is

     SNMP_RET_ERR  Error in operation.	The error code and index have been set
		   in pdu.  No response	PDU has	been constructed.  The caller
		   may construct an error response PDU via

     The function snmp_set() executes an SNMP SET operation.  The arguments
     are the same as for the previous three functions.	The operation of this
     functions is, however, much more complex.

     The SET operation occurs in several stages:

	   1.	For each binding search	the corresponding nodes, check that
		the variable is	writeable and the syntax is ok.	 The writeable
		check can be done only for scalars.  For columns it must be
		done in	the node's operation callback function.

	   2.	For each binding call the node's operation callback with func-
		tion SNMP_OP_SET.  The callback	may create dependencies	or fi-
		nalizers (see below).  For simple scalars the scratch area may
		be enough to handle commit and rollback, for interdependent
		table columns dependencies may be necessary.

	   3.	If the previous	step fails at any point, the node's operation
		callback functions are called for all bindings for which
		SNMP_OP_SET was	executed with SNMP_OP_ROLLBACK,	in the oppo-
		site order.  This allows all variables to undo the effect of
		the SET	operation.  After this all the dependencies are	freed
		and the	finalizers are executed	with a fail flag of 1.	Then
		the function returns to	the caller with	an appropriate error

	   4.	If the SET step	was successful for all bindings, the depen-
		dency callbacks	are executed in	the order in which the depen-
		dencies	were created with an operation of SNMP_DEPOP_COMMIT.
		If any of the dependencies fails, all the committed dependen-
		cies are called	again in the opposite order with SNMP_DE-
		POP_ROLLBACK.  Than for	all bindings from the last to the
		first the node's operation callback is called with
		SNMP_OP_ROLLBACK to undo the effect of SNMP_OP_SET.  At	the
		end the	dependencies are freed and the finalizers are called
		with a fail flag of 1 and the function returns to the caller
		with an	appropriate error indication.

	   5.	If the dependency commits were successful, for each binding
		the node's operation callback is called	with SNMP_OP_COMMIT.
		Any error returned from	the callbacks is ignored (an error
		message	is generated via snmp_error().)

	   6.	Now the	dependencies are freed and the finalizers are called
		with a fail flag of 0.	For each dependency just before	free-
		ing it its callback is called with SNMP_DEPOP_FINISH. Then the
		function returns SNMP_ERR_OK.

     There are to mechanisms to	help in	complex	SET operations:	dependencies
     and finalizers.  A	dependency is used if several bindings depend on each
     other.  A typical example is the creation of a conceptual row, which re-
     quires the	setting	of several columns to succeed.	A dependency is	iden-
     tified by two OIDs.  In the table case, the first oid is typically	the
     table's base OID and the second one the index.  Both of these can easily
     be	generated from the variables OID with asn_slice_oid().	The function
     snmp_dep_lookup() tries to	find a dependency based	on these two OIDs and,
     if	it cannot find one creates a new one.  This means for the table	exam-
     ple, that the function returns the	same dependency	for each of the	col-
     umns of the same table row.  This allows during the SNMP_OP_SET process-
     ing to collect all	information about the row into the dependency.	The
     arguments to snmp_dep_lookup() are: the two OIDs to identify the depen-
     dency (they are copied into newly created dependencies), the size of the
     structure to allocate and the dependency callback.

     When all SNMP_OP_SET operations have succeeded the	dependencies are exe-
     cuted.  At	this stage the dependency callback has all information about
     the given table row that was available in this SET	PDU and	can operate

     It	is guaranteed that each	dependency callback is executed	at minimum
     once - with an operation of SNMP_OP_ROLLBACK.  This ensures that all dy-
     namically allocated resources in a	callback can be	freed correctly.

     The function snmp_make_errresp() makes an error response if an operation
     has failed.  It takes the original	request	PDU (it	will look only on the
     error code	and index fields), the buffer containing the original PDU and
     a buffer for the error PDU.  It copies the	bindings field from the	origi-
     nal PDUs buffer directly to the response PDU and thus does	not depend on
     the decodability of this field.  It may return the	same values as the op-
     eration functions.

     The next four functions allow some	parts of the SET operation to be exe-
     cuted.  This is only used in bsnmpd(1) to implement the configuration as
     a single transaction.  The	function snmp_init_context() creates and ini-
     tializes a	context.  The function snmp_dep_commit() executes SNMP_DE-
     POP_COMMIT	for all	dependencies in	the context stopping at	the first er-
     ror.  The function	snmp_dep_rollback() executes SNMP_DEPOP_ROLLBACK
     starting at the previous of the current dependency	in the context.	 The
     function snmp_dep_finish()	executes SNMP_DEPOP_FINISH for all dependen-

     If	an error occurs	in any of the function an error	indication as de-
     scribed above is returned.	 Additionally the functions may	call snmp_er-
     ror on unexpected errors.

     gensnmptree(1), bsnmpd(1),	bsnmpclient(3),	bsnmplib(3), snmpmod(3)

     This implementation conforms to the applicable IETF RFCs and ITU-T	recom-

     Hartmut Brandt <>

BSD				October	4, 2005				   BSD


Want to link to this manual page? Use this URL:

home | help