1.\" 2.\" Copyright (c) 2004-2005 3.\" Hartmut Brandt. 4.\" All rights reserved. 5.\" Copyright (c) 2001-2003 6.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). 7.\" All rights reserved. 8.\" 9.\" Author: Harti Brandt <harti@FreeBSD.org> 10.\" 11.\" Redistribution and use in source and binary forms, with or without 12.\" modification, are permitted provided that the following conditions 13.\" are met: 14.\" 1. Redistributions of source code must retain the above copyright 15.\" notice, this list of conditions and the following disclaimer. 16.\" 2. Redistributions in binary form must reproduce the above copyright 17.\" notice, this list of conditions and the following disclaimer in the 18.\" documentation and/or other materials provided with the distribution. 19.\" 20.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 24.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30.\" SUCH DAMAGE. 31.\" 32.\" $Begemot: bsnmp/lib/bsnmpagent.3,v 1.10 2005/10/04 08:46:49 brandt_h Exp $ 33.\" 34.Dd October 4, 2005 35.Dt BSNMPAGENT 3 36.Os 37.Sh NAME 38.Nm bsnmpagent , 39.Nm snmp_depop_t , 40.Nm snmp_op_t , 41.Nm tree , 42.Nm tree_size , 43.Nm snmp_trace , 44.Nm snmp_debug , 45.Nm snmp_get , 46.Nm snmp_getnext , 47.Nm snmp_getbulk , 48.Nm snmp_set , 49.Nm snmp_make_errresp , 50.Nm snmp_dep_lookup , 51.Nm snmp_init_context , 52.Nm snmp_dep_commit , 53.Nm snmp_dep_rollback , 54.Nm snmp_dep_finish 55.Nd "SNMP agent library" 56.Sh LIBRARY 57Begemot SNMP library 58.Pq libbsnmp, -lbsnmp 59.Sh SYNOPSIS 60.In asn1.h 61.In snmp.h 62.In snmpagent.h 63.Ft typedef int 64.Fn (*snmp_depop_t) "struct snmp_context *ctx" "struct snmp_dependency *dep" "enum snmp_depop op" 65.Ft typedef int 66.Fn (*snmp_op_t) "struct snmp_context *ctx" "struct snmp_value *val" "u_int len" "u_int idx" "enum snmp_op op" 67.Vt extern struct snmp_node *tree ; 68.Vt extern u_int tree_size ; 69.Vt extern u_int snmp_trace ; 70.Vt extern void (*snmp_debug)(const char *fmt, ...) ; 71.Ft enum snmp_ret 72.Fn snmp_get "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" 73.Ft enum snmp_ret 74.Fn snmp_getnext "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" 75.Ft enum snmp_ret 76.Fn snmp_getbulk "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" 77.Ft enum snmp_ret 78.Fn snmp_set "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" 79.Ft enum snmp_ret 80.Fn snmp_make_errresp "const struct snmp_pdu *pdu" "struct asn_buf *req_b" "struct asn_buf *resp_b" 81.Ft struct snmp_dependency * 82.Fn snmp_dep_lookup "struct snmp_context *ctx" "const struct asn_oid *base" "const struct asn_oid *idx" "size_t alloc" "snmp_depop_t func" 83.Ft struct snmp_context * 84.Fn snmp_init_context "void" 85.Ft int 86.Fn snmp_dep_commit "struct snmp_context *ctx" 87.Ft int 88.Fn snmp_dep_rollback "struct snmp_context *ctx" 89.Ft void 90.Fn snmp_dep_finish "struct snmp_context *ctx" 91.Sh DESCRIPTION 92The SNMP library contains routines to easily build SNMP agent applications 93that use SNMP versions 1 or 2. 94Note, however, that it may be even easier to build an 95.Xr bsnmpd 1 96loadable module, that handles the new MIB (see 97.Xr snmpmod 3 ) . 98.Pp 99Most of the agent routines operate on a global array that the describes the 100complete MIB served by the agent. 101This array is held in the two variables: 102.Bd -literal -offset indent 103extern struct snmp_node *tree; 104extern u_int tree_size; 105.Ed 106.Pp 107The elements of the array are of type 108.Vt struct snmp_node : 109.Bd -literal -offset indent 110typedef int (*snmp_op_t)(struct snmp_context *, struct snmp_value *, 111 u_int, u_int, enum snmp_op); 112 113struct snmp_node { 114 struct asn_oid oid; 115 const char *name; /* name of the leaf */ 116 enum snmp_node_type type; /* type of this node */ 117 enum snmp_syntax syntax; 118 snmp_op_t op; 119 u_int flags; 120 u_int32_t index; /* index data */ 121 void *data; /* application data */ 122 void *tree_data; /* application data */ 123}; 124.Ed 125.Pp 126The fields of this structure are described below. 127.Bl -tag -width "syntax" 128.It Va oid 129Base OID of the scalar or table column. 130.It Va name 131Name of this variable. 132.It Va type 133Type of this variable. 134One of: 135.Bd -literal -offset indent 136enum snmp_node_type { 137 SNMP_NODE_LEAF = 1, 138 SNMP_NODE_COLUMN 139}; 140.Ed 141.It Va syntax 142The SNMP syntax of this variable. 143.It Va op 144The user supplied handler for this variable. 145The handler is called with the following arguments: 146.Bl -tag -width "ctx" 147.It Fa ctx 148A pointer to the context (see below). 149.Li NULL . 150.It Fa val 151The value to be set or retrieved. 152For GETNEXT and GETBULK operations the oid in 153this value is the current OID. 154The function (called in this case only for 155table rows) must find the lexically next existing OID within the same column and 156set the oid and value subfields accordingly. 157If the table column is exhausted the 158function must return 159.Li SNMP_ERR_NOSUCHNAME . 160For all other operations the oid in 161.Fa val 162is the oid to fetch or set. 163.It Fa len 164The length of the base oid without index. 165.It Fa idx 166For table columns this is the index expression from the node (see below). 167.It Fa op 168This is the operation to execute, one of: 169.Bd -literal -offset indent 170enum snmp_op { 171 SNMP_OP_GET = 1, 172 SNMP_OP_GETNEXT, 173 SNMP_OP_SET, 174 SNMP_OP_COMMIT, 175 SNMP_OP_ROLLBACK, 176}; 177.Ed 178.El 179.Pp 180The user handler must return an appropriate SNMP v2 error code. 181If the original 182PDU was a version 1 PDU, the error code is mapped automatically. 183.It Va flags 184Currently only the flag 185.Li SNMP_NODE_CANSET is defined and set for nodes, that can be written or 186created. 187.It Va index 188This word describes the index for table columns. 189Each part of the index takes 4 bits starting at bit 4. 190Bits 0 to 3 hold the number of index parts. 191This arrangement allows for tables with up to seven indexes. 192Each bit group contains the syntax for the index part. 193There are a number of macros to help in parsing this field: 194.Bd -literal -offset indent 195#define SNMP_INDEXES_MAX 7 196#define SNMP_INDEX_SHIFT 4 197#define SNMP_INDEX_MASK 0xf 198#define SNMP_INDEX_COUNT(V) ((V) & SNMP_INDEX_MASK) 199#define SNMP_INDEX(V,I) \e 200 (((V) >> (((I) + 1) * SNMP_INDEX_SHIFT)) & \e 201 SNMP_INDEX_MASK) 202.Ed 203.It Va data 204This field may contain arbitrary data and is not used by the library. 205.El 206.Pp 207The easiest way to construct the node table is 208.Xr gensnmptree 1 . 209Note, that one must be careful when changing the tree while executing a SET 210operation. 211Consult the sources for 212.Xr bsnmpd 1 . 213.Pp 214The global variable 215.Va snmp_trace 216together with the function pointed to by 217.Va snmp_debug 218help in debugging the library and the agent. 219.Va snmp_trace is a bit mask with the following bits: 220.Bd -literal -offset indent 221enum { 222 SNMP_TRACE_GET, 223 SNMP_TRACE_GETNEXT, 224 SNMP_TRACE_SET, 225 SNMP_TRACE_DEPEND, 226 SNMP_TRACE_FIND, 227}; 228.Ed 229.Pp 230Setting a bit to true causes the library to call 231.Fn snmp_debug 232in strategic places with a debug string. 233The library contains a default 234implementation for the debug function that prints a message to standard error. 235.Pp 236Many of the functions use a so called context: 237.Bd -literal -offset indent 238struct snmp_context { 239 u_int var_index; 240 struct snmp_scratch *scratch; 241 struct snmp_dependency *dep; 242 void *data; /* user data */ 243 enum snmp_ret code; /* return code */ 244}; 245 246struct snmp_scratch { 247 void *ptr1; 248 void *ptr2; 249 uint32_t int1; 250 uint32_t int2; 251}; 252.Ed 253.Pp 254The fields are used as follows: 255.Bl -tag -width ".It Va var_index" 256.It Va va_index 257For the node operation callback this is the 258index of the variable binding that should be returned if an error occurs. 259Set by the library. 260In all other functions this is undefined. 261.It Va scratch 262For the node operation callback this is a pointer to a per variable binding 263scratch area that can be used to implement the commit and rollback. 264Set by the library. 265.It Va dep 266In the dependency callback function (see below) this is a pointer to the 267current dependency. 268Set by the library. 269.It Va data 270This is the 271.Fa data 272argument from the call to the library and is not used by the library. 273.El 274.Pp 275The next three functions execute different kinds of GET requests. 276The function 277.Fn snmp_get 278executes an SNMP GET operation, the function 279.Fn snmp_getnext 280executes an SNMP GETNEXT operation and the function 281.Fn snmp_getbulk 282executes an SNMP GETBULK operation. 283For all three functions the response PDU is constructed and encoded 284on the fly. 285If everything is ok, the response PDU is returned in 286.Fa resp 287and 288.Fa resp_b . 289The caller must call 290.Fn snmp_pdu_free 291to free the response PDU in this case. 292One of the following values may be returned: 293.Bl -tag -width ".It Li SNMP_RET_ERR" 294.It Li SNMP_RET_OK 295Operation successful, response PDU may be sent. 296.It Li SNMP_RET_IGN 297Operation failed, no response PDU constructed. 298Request is ignored. 299.It Li SNMP_RET_ERR 300Error in operation. 301The error code and index have been set in 302.Fa pdu . 303No response PDU has been constructed. 304The caller may construct an error response PDU via 305.Fn snmp_make_errresp . 306.El 307.Pp 308The function 309.Fn snmp_set 310executes an SNMP SET operation. 311The arguments are the same as for the previous 312three functions. 313The operation of this functions is, however, much more complex. 314.Pp 315The SET operation occurs in several stages: 316.Bl -enum -offset indent 317.It 318For each binding search the corresponding nodes, check that the 319variable is writeable and the syntax is ok. 320The writeable check can be done only for scalars. 321For columns it must be done in the node's operation callback function. 322.It 323For each binding call the node's operation callback with function SNMP_OP_SET. 324The callback may create dependencies or finalizers (see below). 325For simple 326scalars the scratch area may be enough to handle commit and rollback, for 327interdependent table columns dependencies may be necessary. 328.It 329If the previous step fails at any point, the node's operation callback 330functions are called for all bindings for which SNMP_OP_SET was executed 331with SNMP_OP_ROLLBACK, in the opposite order. 332This allows all variables to undo the effect of the SET operation. 333After this all the dependencies are freed 334and the finalizers are executed with a fail flag of 1. 335Then the function 336returns to the caller with an appropriate error indication. 337.It 338If the SET step was successful for all bindings, the dependency callbacks 339are executed in the order in which the dependencies were created with an 340operation of SNMP_DEPOP_COMMIT. 341If any of the dependencies fails, all the 342committed dependencies are called again in the opposite order 343with SNMP_DEPOP_ROLLBACK. 344Than for all bindings from the last to the first 345the node's operation callback is called with SNMP_OP_ROLLBACK to undo 346the effect of SNMP_OP_SET. 347At the end the dependencies are freed and the finalizers are called with 348a fail flag of 1 and the function returns to the caller with an appropriate 349error indication. 350.It 351If the dependency commits were successful, for each binding the node's 352operation callback is called with SNMP_OP_COMMIT. 353Any error returned from 354the callbacks is ignored (an error message is generated via 355.Fn snmp_error ). 356.It 357Now the dependencies are freed and the finalizers are called 358with a fail flag of 0. 359For each dependency just before freeing it 360its callback is called with 361.Li SNMP_DEPOP_FINISH. 362Then the function returns 363.Li SNMP_ERR_OK . 364.El 365.Pp 366There are to mechanisms to help in complex SET operations: dependencies and 367finalizers. 368A dependency is used if several bindings depend on each other. 369A typical example is the creation of a conceptual row, which requires 370the setting of several columns to succeed. 371A dependency is identified by 372two OIDs. 373In the table case, the first oid is typically the table's base OID 374and the second one the index. 375Both of these can easily be generated from the 376variables OID with 377.Fn asn_slice_oid . 378The function 379.Fn snmp_dep_lookup 380tries to find a dependency based on these two OIDs and, if it cannot find one 381creates a new one. 382This means for the table example, that the function 383returns the same dependency for each of the columns of the same table row. 384This allows during the SNMP_OP_SET processing to collect all information 385about the row into the dependency. 386The arguments to 387.Fn snmp_dep_lookup 388are: the two OIDs to identify the dependency (they are copied into newly 389created dependencies), the size of the structure to allocate and 390the dependency callback. 391.Pp 392When all SNMP_OP_SET operations have succeeded the dependencies are executed. 393At this stage the dependency callback has all information about the given 394table row that was available in this SET PDU and can operate accordingly. 395.Pp 396It is guaranteed that each dependency callback is executed at minimum once 397- with an operation of 398.Li SNMP_OP_ROLLBACK . 399This ensures that all dynamically allocated resources in a callback can be 400freed correctly. 401.Pp 402The function 403.Fn snmp_make_errresp 404makes an error response if an operation has failed. 405It takes the original request PDU (it will look only on the error code and 406index fields), the buffer containing the original PDU and a buffer for the 407error PDU. 408It copies the bindings field from the original PDUs buffer directly to 409the response PDU and thus does not depend on the decodability of this field. 410It may return the same values as the operation functions. 411.Pp 412The next four functions allow some parts of the SET operation to be executed. 413This is only used in 414.Xr bsnmpd 1 415to implement the configuration as a single transaction. 416The function 417.Fn snmp_init_context 418creates and initializes a context. 419The function 420.Fn snmp_dep_commit 421executes SNMP_DEPOP_COMMIT for all dependencies in the context stopping at 422the first error. 423The function 424.Fn snmp_dep_rollback 425executes SNMP_DEPOP_ROLLBACK starting at the previous of the current 426dependency in the context. 427The function 428.Fn snmp_dep_finish 429executes SNMP_DEPOP_FINISH for all dependencies. 430.Sh DIAGNOSTICS 431If an error occurs in any of the function an error indication as described 432above is returned. 433Additionally the functions may call snmp_error on unexpected errors. 434.Sh SEE ALSO 435.Xr gensnmptree 1 , 436.Xr bsnmpd 1 , 437.Xr bsnmpclient 3 , 438.Xr bsnmplib 3 , 439.Xr snmpmod 3 440.Sh STANDARDS 441This implementation conforms to the applicable IETF RFCs and ITU-T 442recommendations. 443.Sh AUTHORS 444.An Hartmut Brandt Aq harti@FreeBSD.org 445