2 .\" Copyright (c) 2004-2005
4 .\" All rights reserved.
5 .\" Copyright (c) 2001-2003
6 .\" Fraunhofer Institute for Open Communication Systems (FhG Fokus).
7 .\" All rights reserved.
9 .\" Author: Harti Brandt <harti@FreeBSD.org>
11 .\" Redistribution and use in source and binary forms, with or without
12 .\" modification, are permitted provided that the following conditions
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.
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
32 .\" $Begemot: bsnmp/snmpd/snmpmod.3,v 1.14 2005/10/04 13:30:35 brandt_h Exp $
38 .Nm INSERT_OBJECT_OID_LINK_INDEX ,
39 .Nm INSERT_OBJECT_INT_LINK_INDEX ,
40 .Nm FIND_OBJECT_OID_LINK_INDEX ,
41 .Nm NEXT_OBJECT_OID_LINK_INDEX ,
42 .Nm FIND_OBJECT_INT_LINK_INDEX ,
43 .Nm NEXT_OBJECT_INT_LINK_INDEX ,
44 .Nm INSERT_OBJECT_OID_LINK ,
45 .Nm INSERT_OBJECT_INT_LINK ,
46 .Nm FIND_OBJECT_OID_LINK ,
47 .Nm NEXT_OBJECT_OID_LINK ,
48 .Nm FIND_OBJECT_INT_LINK ,
49 .Nm NEXT_OBJECT_INT_LINK ,
50 .Nm INSERT_OBJECT_OID ,
51 .Nm INSERT_OBJECT_INT ,
69 .Nm timer_start_repeat ,
79 .Nm snmp_input_start ,
80 .Nm snmp_input_finish ,
100 .Nm index_compare_off ,
103 .Nd "SNMP daemon loadable module interface"
106 .Pq libbsnmp, -lbsnmp
109 .Fn INSERT_OBJECT_OID_LINK_INDEX "PTR" "LIST" "LINK" "INDEX"
110 .Fn INSERT_OBJECT_INT_LINK_INDEX "PTR" "LIST" "LINK" "INDEX"
111 .Fn FIND_OBJECT_OID_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX"
112 .Fn FIND_OBJECT_INT_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX"
113 .Fn NEXT_OBJECT_OID_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX"
114 .Fn NEXT_OBJECT_INT_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX"
115 .Fn INSERT_OBJECT_OID_LINK "PTR" "LIST" "LINK"
116 .Fn INSERT_OBJECT_INT_LINK "PTR" "LIST" "LINK"
117 .Fn FIND_OBJECT_OID_LINK "LIST" "OID" "SUB" "LINK"
118 .Fn FIND_OBJECT_INT_LINK "LIST" "OID" "SUB" "LINK"
119 .Fn NEXT_OBJECT_OID_LINK "LIST" "OID" "SUB" "LINK"
120 .Fn NEXT_OBJECT_INT_LINK "LIST" "OID" "SUB" "LINK"
121 .Fn INSERT_OBJECT_OID "PTR" "LIST"
122 .Fn INSERT_OBJECT_INT "PTR" "LIST"
123 .Fn FIND_OBJECT_OID "LIST" "OID" "SUB"
124 .Fn FIND_OBJECT_INT "LIST" "OID" "SUB"
125 .Fn NEXT_OBJECT_OID "LIST" "OID" "SUB"
126 .Fn NEXT_OBJECT_INT "LIST" "OID" "SUB"
127 .Vt extern uint64_t this_tick ;
128 .Vt extern uint64_t start_tick ;
131 .Vt extern struct systemg systemg ;
133 .Fn comm_define "u_int priv" "const char *descr" "struct lmodule *mod" "const char *str"
135 .Fn comm_string "u_int comm"
136 .Vt extern u_int community ;
137 .Vt extern const struct asn_oid oid_zeroDotZero ;
139 .Fn reqid_allocate "int size" "struct lmodule *mod"
141 .Fn reqid_next "u_int type"
143 .Fn reqid_base "u_int type"
145 .Fn reqid_istype "int32_t reqid" "u_int type"
147 .Fn reqid_type "int32_t reqid"
149 .Fn timer_start "u_int ticks" "void (*func)(void *)" "void *uarg" "struct lmodule *mod"
151 .Fn timer_start_repeat "u_int ticks" "u_int repeat_ticks" "void (*func)(void *)" "void *uarg" "struct lmodule *mod"
153 .Fn timer_stop "void *timer_id"
155 .Fn fd_select "int fd" "void (*func)(int, void *)" "void *uarg" "struct lmodule *mod"
157 .Fn fd_deselect "void *fd_id"
159 .Fn fd_suspend "void *fd_id"
161 .Fn fd_resume "void *fd_id"
163 .Fn or_register "const struct asn_oid *oid" "const char *descr" "struct lmodule *mod"
165 .Fn or_unregister "u_int or_id"
167 .Fn buf_alloc "int tx"
169 .Fn buf_size "int tx"
170 .Ft enum snmpd_input_err
172 .Fa "const u_char *buf" "size_t len" "const char *source"
173 .Fa "struct snmp_pdu *pdu" "int32_t *ip" "size_t *pdulen"
175 .Ft enum snmpd_input_err
176 .Fo snmp_input_finish
177 .Fa "struct snmp_pdu *pdu" "const u_char *rcvbuf"
178 .Fa "size_t rcvlen" "u_char *sndbuf" "size_t *sndlen" "const char *source"
179 .Fa "enum snmpd_input_err ierr" "int32_t ip" "void *data"
183 .Fa "struct snmp_pdu *pdu" "u_char *sndbuf" "size_t *sndlen"
184 .Fa "const char *dest"
188 .Fa "void *trans" "const struct asn_oid *port"
189 .Fa "struct snmp_pdu *pdu" "const struct sockaddr *addr" "socklen_t addrlen"
192 .Fn snmp_send_trap "const struct asn_oid *oid" "..."
194 .Fn string_save "struct snmp_value *val" "struct snmp_context *ctx" "ssize_t req_size" "u_char **strp"
196 .Fn string_commit "struct snmp_context *ctx"
198 .Fn string_rollback "struct snmp_context *ctx" "u_char **strp"
200 .Fn string_get "struct snmp_value *val" "const u_char *str" "ssize_t len"
202 .Fn string_get_max "struct snmp_value *val" "const u_char *str" "ssize_t len" "size_t maxlen"
204 .Fn string_free "struct snmp_context *ctx"
206 .Fn ip_save "struct snmp_value *val" "struct snmp_context *ctx" "u_char *ipa"
208 .Fn ip_rollback "struct snmp_context *ctx" "u_char *ipa"
210 .Fn ip_commit "struct snmp_context *ctx"
212 .Fn ip_get "struct snmp_value *val" "u_char *ipa"
214 .Fn oid_save "struct snmp_value *val" "struct snmp_context *ctx" "struct asn_oid *oid"
216 .Fn oid_rollback "struct snmp_context *ctx" "struct asn_oid *oid"
218 .Fn oid_commit "struct snmp_context *ctx"
220 .Fn oid_get "struct snmp_value *val" "const struct asn_oid *oid"
222 .Fn index_decode "const struct asn_oid *oid" "u_int sub" "u_int code" "..."
224 .Fn index_compare "const struct asn_oid *oid1" "u_int sub" "const struct asn_oid *oid2"
226 .Fn index_compare_off "const struct asn_oid *oid1" "u_int sub" "const struct asn_oid *oid2" "u_int off"
228 .Fn index_append "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src"
230 .Fn index_append_off "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" "u_int off"
234 SNMP daemon implements a minimal MIB which consists of the system group, part
235 of the SNMP MIB, a private configuration MIB, a trap destination table, a
236 UDP port table, a community table, a module table, a statistics group and
238 All other MIBs are support through loadable modules.
241 to use for task, that are not the classical SNMP task.
242 .Ss MODULE LOADING AND UNLOADING
243 Modules are loaded by writing to the module table.
244 This table is indexed by a string, that identifies the module to the daemon.
245 This identifier is used
246 to select the correct configuration section from the configuration files and
247 to identify resources allocated to this module.
248 A row in the module table is
249 created by writing a string of non-zero length to the
250 .Va begemotSnmpdModulePath
252 This string must be the complete path to the file containing the module.
253 A module can be unloaded by writing a zero length string to the path column
256 Modules may depend on each other an hence must be loaded in the correct order.
257 The dependencies are listed in the corresponding manual pages.
259 Upon loading a module the SNMP daemon expects the module file to a export
262 This symbol should be a variable of type
263 .Vt struct snmp_module :
264 .Bd -literal -offset indent
265 typedef enum snmpd_proxy_err (*proxy_err_f)(struct snmp_pdu *, void *,
266 const struct asn_oid *, const struct sockaddr *, socklen_t,
267 enum snmpd_input_err, int32_t);
272 int (*init)(struct lmodule *, int argc, char *argv[]);
276 void (*config)(void);
279 const struct snmp_node *tree;
281 void (*loading)(const struct lmodule *, int);
285 This structure must be statically initialized and its fields have the
287 .Bl -tag -width ".It Va tree_size"
289 This is a string that will be visible in the module table.
290 It should give some hint about the function of this module.
292 This function is called upon loading the module.
293 The module pointer should
294 be stored by the module because it is needed in other calls and the
295 argument vector will contain the arguments to this module from the daemons
297 This function should return 0 if everything is ok or an UNIX error code (see
299 Once the function returns 0, the
301 function is called when the module is unloaded.
303 The module is unloaded.
304 This gives the module a chance to free resources that
305 are not automatically freed.
306 Be sure to free all memory, because daemons tend to run very long.
307 This function pointer may be
311 If this function pointer is not
313 the function pointed to by it is called whenever the daemon is going
314 to wait for an event.
315 Try to avoid using this feature.
317 Whenever the daemon receives a
319 it dumps it internal state via
325 it is called by the daemon to dump the state of the module.
327 Whenever the daemon receives a
329 signal it re-reads its configuration file.
334 it is called after reading the configuration file to give the module a chance
335 to adapt to the new configuration.
339 this function is called after successful loading and initializing the module
340 to start its actual operation.
342 If the daemon receives a PDU and that PDU has a community string whose
343 community was registered by this module and
347 than this function is called to handle the PDU.
349 This is a pointer to the node array for the MIB tree implemented by this module.
351 This is the number of nodes in
354 If this pointer is not
356 it is called whenever another module was loaded or unloaded.
358 pointer to that module and a flag that is 0 for unloading and 1 for loading.
361 When everything is ok, the daemon merges the module's MIB tree into its current
362 global tree, calls the modules
365 If this function returns an error, the modules MIB tree is removed from
366 the global one and the module is unloaded.
367 If initialization is successful, the modules
372 functions of all modules (including the loaded one) are called.
374 When the module is unloaded, its MIB tree is removed from the global one,
375 the communities, request id ranges, running timers and selected file
376 descriptors are released, the
378 function is called, the module file is unloaded and the
380 functions of all other modules are called.
381 .Ss IMPLEMENTING TABLES
382 There are a number of macros designed to help implementing SNMP tables.
383 A problem while implementing a table is the support for the GETNEXT operator.
384 The GETNEXT operation has to find out whether, given an arbitrary OID, the
385 lessest table row, that has an OID higher than the given OID.
387 to do this is to keep the table as an ordered list of structures each one
388 of which contains an OID that is the index of the table row.
389 This allows easy removal, insertion and search.
391 The helper macros assume, that the table is organized as a TAILQ (see
393 and each structure contains a
395 that is used as index.
396 For simple tables with only a integer or unsigned index, an alternate form
397 of the macros is available, that presume the existence of an integer or
398 unsigned field as index field.
400 The macros have name of the form
401 .Bd -literal -offset indent
402 {INSERT,FIND,NEXT}_OBJECT_{OID,INT}[_LINK[_INDEX]]
407 macros are used in the SET operation to insert a new table row into the table.
410 macros are used in the GET operation to find a specific row in the table.
413 macros are used in the GETNEXT operation to find the next row in the table.
414 The last two macros return a pointer to the row structure if a row is found,
419 assume the existence of a
421 that is used as index, the macros
423 assume the existence of an unsigned integer field that is used as index.
427 allow the explicit naming of the index field in the parameter
429 whereas the other macros assume that this field is named
433 allow the explicit naming of the link field of the tail queues, the others
434 assume that the link field is named
436 Explicitly naming the link field may be necessary if the same structures
437 are held in two or more different tables.
439 The arguments to the macros are as follows:
440 .Bl -tag -width "INDEX"
442 A pointer to the new structure to be inserted into the table.
444 A pointer to the tail queue head.
446 The name of the link field in the row structure.
448 The name of the index field in the row structure.
454 argument to the node operation callback.
455 This is the OID to search for.
457 This is the index of the start of the table index in the OID pointed to
460 This is usually the same as the
462 argument to the node operation callback.
464 .Ss DAEMON TIMESTAMPS
467 contains the tick (there are 100 SNMP ticks in a second) when
468 the current PDU processing was started.
471 contains the tick when the daemon was started.
474 returns the current tick.
475 The number of ticks since the daemon was started
477 .Bd -literal -offset indent
478 get_ticks() - start_tick
481 The scalar fields of the system group are held in the global variable
483 .Bd -literal -offset indent
486 struct asn_oid object_id;
491 uint32_t or_last_change;
495 The SNMP daemon implements a community table.
496 On recipte of a request message
497 the community string in that message is compared to each of the community
498 strings in that table, if a match is found, the global variable
500 is set to the community identifier for that community.
501 Community identifiers are unsigned integers.
502 For the three standard communities there are three constants defined:
503 .Bd -literal -offset indent
504 #define COMM_INITIALIZE 0
512 while the assignments in the configuration file are processed.
517 when the community strings for the read-write or read-only community are found
520 Modules can define additional communities.
521 This may be necessary to provide
522 transport proxying (a PDU received on one communication link is proxied to
523 another link) or to implement non-UDP access points to SNMP.
524 A new community is defined with the function
526 It takes the following parameters:
527 .Bl -tag -width ".It Fa descr"
529 This is an integer identifying the community to the module.
530 Each module has its own namespace with regard to this parameter.
531 The community table is indexed with the module name and this identifier.
533 This is a string providing a human readable description of the community.
534 It is visible in the community table.
536 This is the module defining the community.
538 This is the initial community string.
541 The function returns a globally unique community identifier.
543 received who's community string matches, this identifier is set into the global
548 returns the current community string for the given community.
550 All communities defined by a module are automatically released when the module
555 contains the OID 0.0.
556 .Ss REQUEST ID RANGES
557 For modules that implement SNMP client functions besides SNMP agent functions
558 it may be necessary to identify SNMP requests by their identifier to allow
559 easier routing of responses to the correct sub-system.
561 provide a way to acquire globally non-overlapping sub-ranges of the entire
564 A request id range is allocated with
566 The arguments are: the size of the range and the module allocating the range.
567 For example, the call
568 .Bd -literal -offset indent
569 id = reqid_allocate(1000, module);
572 allocates a range of 1000 request ids.
573 The function returns the request
574 id range identifier or 0 if there is not enough identifier space.
577 returns the lowest request id in the given range.
579 Request id are allocated starting at the lowest one linear throughout the range.
580 If the client application may have a lot of outstanding request the range
581 must be large enough so that an id is not reused until it is really expired.
583 returns the sequentially next id in the range.
587 checks whether the request id
589 is within the range identified by
593 returns the range identifier for the given
595 or 0 if the request id is in none of the ranges.
597 The SNMP daemon supports an arbitrary number of timers with SNMP tick granularity.
600 arranges for the callback
602 to be called with the argument
606 SNMP ticks have expired.
608 is the module that starts the timer.
609 These timers are one-shot, they are not restarted.
610 Repeatable timers are started with
611 .Fn timer_start_repeat
612 which takes an additional argument
616 gives the number of ticks until the first execution of the callback, while
618 is the number of ticks between invocations of the callback.
619 Note, that currently the number of initial ticks silently may be set identical
620 to the number of ticks between callback invocations.
621 The function returns a timer identifier that can be used to stop the timer via
623 If a module is unloaded all timers started by the module that have not expired
625 .Ss FILE DESCRIPTOR SUPPORT
626 A module may need to get input from socket file descriptors without blocking
627 the daemon (for example to implement alternative SNMP transports).
631 causes the callback function
633 to be called with the file descriptor
635 and the user argument
637 whenever the file descriptor
639 can be read or has a close condition.
640 If the file descriptor is not in
641 non-blocking mode, it is set to non-blocking mode.
642 If the callback is not needed anymore,
644 may be called with the value returned from
646 All file descriptors selected by a module are automatically deselected when
647 the module is unloaded.
649 To temporarily suspend the file descriptor registration
652 This also causes the file descriptor to be switched back to
653 blocking mode if it was blocking prior the call to
655 This is necessary to do synchronous input on a selected socket.
661 The system group contains an object resource table.
662 A module may create an entry in this table by calling
666 to be registered, a textual description in
668 and a pointer to the module
670 The registration can be removed with
672 All registrations of a module are automatically removed if the module is
674 .Ss TRANSMIT AND RECEIVE BUFFERS
675 A buffer is allocated via
677 The argument must be 1 for transmit and 0 for receive buffers.
678 The function may return
680 if there is no memory available.
681 The current buffersize can be obtained with
684 For modules that need to do their own PDU processing (for example for proxying)
685 the following functions are available:
689 decodes the PDU, searches the community, and sets the global
691 It returns one of the following error codes:
692 .Bl -tag -width ".It Er SNMPD_INPUT_VALBADLEN"
693 .It Er SNMPD_INPUT_OK
694 Everything ok, continue with processing.
695 .It Er SNMPD_INPUT_FAILED
696 The PDU could not be decoded, has a wrong version or an unknown
698 .It Er SNMPD_INPUT_VALBADLEN
699 A SET PDU had a value field in a binding with a wrong length field in an
701 .It Er SNMPD_INPUT_VALRANGE
702 A SET PDU had a value field in a binding with a value that is out of range
703 for the given ASN.1 type.
704 .It Er SNMPD_INPUT_VALBADENC
705 A SET PDU had a value field in a binding with wrong ASN.1 encoding.
706 .It Er SNMPD_INPUT_TRUNC
707 The buffer appears to contain a valid begin of a PDU, but is too short.
708 For streaming transports this means that the caller must save what he
709 already has and trying to obtain more input and reissue this input to
711 For datagram transports this means that part of the
712 datagram was lost and the input should be ignored.
716 .Fn snmp_input_finish
717 does the other half of processing: if
719 did not return OK, tries to construct an error response.
720 If the start was OK, it calls the correct function from
722 to execute the request and depending on the outcome constructs a response or
723 error response PDU or ignores the request PDU.
727 .Er SNMPD_INPUT_FAILED .
728 In the first case a response PDU was constructed and should be sent.
732 takes a PDU and encodes it.
736 takes a PDU, encodes it and sends it through the given port (identified by
737 the transport and the index in the port table) to the given address.
741 sends a trap to all trap destinations.
742 The arguments are the
744 identifying the trap and a NULL-terminated list of
745 .Vt struct snmp_value
746 pointers that are to be inserted into the trap binding list.
747 .Ss SIMPLE ACTION SUPPORT
748 For simple scalar variables that need no dependencies a number of support
749 functions is available to handle the set, commit, rollback and get.
751 The following functions are used for OCTET STRING scalars, either NUL terminated
753 .Bl -tag -width "XXXXXXXXX"
755 should be called for SNMP_OP_SET.
759 are the resp\&.\& arguments to the node callback.
761 is a pointer to the pointer that holds the current value and
763 should be -1 if any size of the string is acceptable or a number larger or
764 equal zero if the string must have a specific size.
766 the old value in the scratch area (note, that any initial value must have
769 allocates a new string, copies over the new value, NUL-terminates it and
770 sets the new current value.
772 simply frees the saved old value in the scratch area.
773 .It Fn string_rollback
774 frees the new value, and puts back the old one.
776 is used for GET or GETNEXT.
778 .It Fn string_get_max
779 can be used instead of
781 to ensure that the returned string has a certain maximum length.
784 is -1, the length is computed via
786 from the current string value.
787 If the current value is NULL,
788 a OCTET STRING of zero length is returned.
790 must be called if either rollback or commit fails to free the saved old value.
793 The following functions are used to process scalars of type IP-address:
794 .Bl -tag -width "XXXXXXXXX"
796 Saves the current value in the scratch area and sets the new value from
801 Restores the old IP address from the scratch area.
803 Retrieves the IP current address.
806 The following functions handle OID-typed variables:
807 .Bl -tag -width "XXXXXXXXX"
809 Saves the current value in the scratch area by allocating a
813 and sets the new value from
816 Frees the old value in the scratch area.
818 Restores the old OID from the scratch area and frees the old OID.
822 .Ss TABLE INDEX HANDLING
823 The following functions help in handling table indexes:
824 .Bl -tag -width "XXXXXXXXX"
826 Decodes the index part of the OID.
829 must be a pointer to the
833 argument of the node callback.
836 argument must be the index of the start of the index in the OID (this is
839 argument to the node callback).
841 is the index expression (parameter
843 to the node callback).
844 These parameters are followed by parameters depending on the syntax of the index
846 .Bl -tag -width ".It Li OCTET STRING"
849 expected as argument.
852 expected as argument.
853 Note, that this syntax is illegal for indexes.
859 expected as arguments.
860 A buffer is allocated to hold the decoded string.
864 is expected as argument.
868 expected as argument that points to a buffer of at least four byte.
869 .It Li COUNTER, GAUGE, TIMETICKS
874 No argument expected.
877 compares the current variable with an OID.
881 come from the node callback arguments
887 is the OID to compare to.
888 The function returns -1, 0, +1 when the
889 variable is lesser, equal, higher to the given OID.
891 must contain only the index part of the table column.
892 .It Fn index_compare_off
895 except that it takes an additional parameter
897 that causes it to ignore the first
899 components of both indexes.
903 beginning at position
907 .It Fn index_append_off
910 beginning at position
914 beginning at position
926 This implementation conforms to the applicable IETF RFCs and ITU-T
929 .An Hartmut Brandt Aq harti@FreeBSD.org