summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormartijn <martijn@openbsd.org>2020-10-26 15:45:56 +0000
committermartijn <martijn@openbsd.org>2020-10-26 15:45:56 +0000
commit81180db98f9aa7483a49bb5ffc9e320f173da837 (patch)
tree9f9f0c2199d4470c677e91bb1fa50cf3c7f28636
parentImprove I/O functions to match Linux: (diff)
downloadwireguard-openbsd-81180db98f9aa7483a49bb5ffc9e320f173da837.tar.xz
wireguard-openbsd-81180db98f9aa7483a49bb5ffc9e320f173da837.zip
s/agentx_/ax_/g and s/subagentx_/agentx_/g
Requested by and OK deraadt@
-rw-r--r--lib/libagentx/Makefile8
-rw-r--r--lib/libagentx/Symbols.list122
-rw-r--r--lib/libagentx/agentx.3645
-rw-r--r--lib/libagentx/agentx.c4780
-rw-r--r--lib/libagentx/agentx.h337
-rw-r--r--lib/libagentx/agentx_internal.h124
-rw-r--r--lib/libagentx/agentx_log.c316
-rw-r--r--lib/libagentx/ax.c1359
-rw-r--r--lib/libagentx/ax.h232
-rw-r--r--lib/libagentx/shlib_version2
-rw-r--r--lib/libagentx/subagentx.3645
-rw-r--r--lib/libagentx/subagentx.c4003
-rw-r--r--lib/libagentx/subagentx.h147
-rw-r--r--lib/libagentx/subagentx_internal.h124
-rw-r--r--lib/libagentx/subagentx_log.c316
15 files changed, 6580 insertions, 6580 deletions
diff --git a/lib/libagentx/Makefile b/lib/libagentx/Makefile
index 82c255f9786..cf4fb7f0767 100644
--- a/lib/libagentx/Makefile
+++ b/lib/libagentx/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.1 2020/09/16 10:48:52 martijn Exp $
+# $OpenBSD: Makefile,v 1.2 2020/10/26 15:45:56 martijn Exp $
LIB= agentx
-SRCS= agentx.c subagentx.c subagentx_log.c
-HDRS= subagentx.h
-MAN= subagentx.3
+SRCS= ax.c agentx.c agentx_log.c
+HDRS= agentx.h
+MAN= agentx.3
CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
diff --git a/lib/libagentx/Symbols.list b/lib/libagentx/Symbols.list
index b31c7b0d95f..95804e1616d 100644
--- a/lib/libagentx/Symbols.list
+++ b/lib/libagentx/Symbols.list
@@ -1,61 +1,61 @@
-subagentx_log_fatal
-subagentx_log_warn
-subagentx_log_info
-subagentx_log_debug
-subagentx
-subagentx_connect
-subagentx_read
-subagentx_write
-subagentx_wantwrite
-subagentx_free
-subagentx_session
-subagentx_session_free
-subagentx_context
-subagentx_context_object_find
-subagentx_context_object_nfind
-subagentx_context_uptime
-subagentx_context_free
-subagentx_agentcaps
-subagentx_agentcaps_free
-subagentx_region
-subagentx_region_free
-subagentx_index_integer_new
-subagentx_index_integer_any
-subagentx_index_integer_value
-subagentx_index_integer_dynamic
-subagentx_index_string_dynamic
-subagentx_index_nstring_dynamic
-subagentx_index_oid_dynamic
-subagentx_index_noid_dynamic
-subagentx_index_ipaddress_dynamic
-subagentx_index_free
-subagentx_object
-subagentx_object_free
-subagentx_varbind_integer
-subagentx_varbind_string
-subagentx_varbind_nstring
-subagentx_varbind_printf
-subagentx_varbind_null
-subagentx_varbind_oid
-subagentx_varbind_object
-subagentx_varbind_index
-subagentx_varbind_ipaddress
-subagentx_varbind_counter32
-subagentx_varbind_gauge32
-subagentx_varbind_timeticks
-subagentx_varbind_opaque
-subagentx_varbind_counter64
-subagentx_varbind_notfound
-subagentx_varbind_error
-subagentx_varbind_request
-subagentx_varbind_get_object
-subagentx_varbind_get_index_integer
-subagentx_varbind_get_index_string
-subagentx_varbind_get_index_oid
-subagentx_varbind_get_index_ipaddress
-subagentx_varbind_set_index_integer
-subagentx_varbind_set_index_string
-subagentx_varbind_set_index_nstring
-subagentx_varbind_set_index_oid
-subagentx_varbind_set_index_object
-subagentx_varbind_set_index_ipaddress
+agentx_log_fatal
+agentx_log_warn
+agentx_log_info
+agentx_log_debug
+agentx
+agentx_connect
+agentx_read
+agentx_write
+agentx_wantwrite
+agentx_free
+agentx_session
+agentx_session_free
+agentx_context
+agentx_context_object_find
+agentx_context_object_nfind
+agentx_context_uptime
+agentx_context_free
+agentx_agentcaps
+agentx_agentcaps_free
+agentx_region
+agentx_region_free
+agentx_index_integer_new
+agentx_index_integer_any
+agentx_index_integer_value
+agentx_index_integer_dynamic
+agentx_index_string_dynamic
+agentx_index_nstring_dynamic
+agentx_index_oid_dynamic
+agentx_index_noid_dynamic
+agentx_index_ipaddress_dynamic
+agentx_index_free
+agentx_object
+agentx_object_free
+agentx_varbind_integer
+agentx_varbind_string
+agentx_varbind_nstring
+agentx_varbind_printf
+agentx_varbind_null
+agentx_varbind_oid
+agentx_varbind_object
+agentx_varbind_index
+agentx_varbind_ipaddress
+agentx_varbind_counter32
+agentx_varbind_gauge32
+agentx_varbind_timeticks
+agentx_varbind_opaque
+agentx_varbind_counter64
+agentx_varbind_notfound
+agentx_varbind_error
+agentx_varbind_request
+agentx_varbind_get_object
+agentx_varbind_get_index_integer
+agentx_varbind_get_index_string
+agentx_varbind_get_index_oid
+agentx_varbind_get_index_ipaddress
+agentx_varbind_set_index_integer
+agentx_varbind_set_index_string
+agentx_varbind_set_index_nstring
+agentx_varbind_set_index_oid
+agentx_varbind_set_index_object
+agentx_varbind_set_index_ipaddress
diff --git a/lib/libagentx/agentx.3 b/lib/libagentx/agentx.3
new file mode 100644
index 00000000000..0db3d32454d
--- /dev/null
+++ b/lib/libagentx/agentx.3
@@ -0,0 +1,645 @@
+.\" $OpenBSD: agentx.3,v 1.1 2020/10/26 15:45:56 martijn Exp $
+.\"
+.\" Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: October 26 2020 $
+.Dt AGENTX 3
+.Os
+.Sh NAME
+.Nm agentx_log_fatal ,
+.Nm agentx_log_warn ,
+.Nm agentx_log_info ,
+.Nm agentx_log_debug ,
+.Nm agentx ,
+.Nm agentx_connect ,
+.Nm agentx_read ,
+.Nm agentx_write ,
+.Nm agentx_wantwrite ,
+.Nm agentx_free ,
+.Nm agentx_session ,
+.Nm agentx_session_free ,
+.Nm agentx_context ,
+.Nm agentx_context_object_find ,
+.Nm agentx_context_object_nfind ,
+.Nm agentx_context_uptime ,
+.Nm agentx_context_free ,
+.Nm agentx_region ,
+.Nm agentx_region_free ,
+.Nm agentx_agentcaps ,
+.Nm agentx_agentcaps_free ,
+.Nm agentx_index_integer_new ,
+.Nm agentx_index_integer_any ,
+.Nm agentx_index_integer_value ,
+.Nm agentx_index_integer_dynamic ,
+.Nm agentx_index_string_dynamic ,
+.Nm agentx_index_nstring_dynamic ,
+.Nm agentx_index_oid_dynamic ,
+.Nm agentx_index_noid_dynamic ,
+.Nm agentx_index_ipaddress_dynamic ,
+.Nm agentx_index_free ,
+.Nm agentx_object ,
+.Nm agentx_object_free ,
+.Nm agentx_varbind_integer ,
+.Nm agentx_varbind_string ,
+.Nm agentx_varbind_nstring ,
+.Nm agentx_varbind_printf ,
+.Nm agentx_varbind_null ,
+.Nm agentx_varbind_oid ,
+.Nm agentx_varbind_object ,
+.Nm agentx_varbind_index ,
+.Nm agentx_varbind_ipaddress ,
+.Nm agentx_varbind_counter32 ,
+.Nm agentx_varbind_gauge32 ,
+.Nm agentx_varbind_timeticks ,
+.Nm agentx_varbind_opaque ,
+.Nm agentx_varbind_counter64 ,
+.Nm agentx_varbind_notfound ,
+.Nm agentx_varbind_error ,
+.Nm agentx_varbind_request ,
+.Nm agentx_varbind_get_index_integer ,
+.Nm agentx_varbind_get_index_string ,
+.Nm agentx_varbind_get_index_oid ,
+.Nm agentx_varbind_get_index_ipaddress ,
+.Nm agentx_varbind_set_index_integer ,
+.Nm agentx_varbind_set_index_string ,
+.Nm agentx_varbind_set_index_nstring ,
+.Nm agentx_varbind_set_index_oid ,
+.Nm agentx_varbind_set_index_object ,
+.Nm agentx_varbind_set_index_ipaddress
+.Nd manage an interface to an agentx master
+.Sh SYNOPSIS
+.In agentx.h
+.Ft extern void
+.Fn (*agentx_log_fatal) "const char *fmt" ...
+.Ft extern void
+.Fn (*agentx_log_warn) "const char *fmt" ...
+.Ft extern void
+.Fn (*agentx_log_info) "const char *fmt" ...
+.Ft extern void
+.Fn (*agentx_log_debug) "const char *fmt" ...
+.Ft struct agentx *
+.Fn agentx "void (*nofd)(struct agentx *, void *, int)" "void *cookie"
+.Ft void
+.Fn agentx_connect "struct agentx *sa" "int fd"
+.Ft void
+.Fn agentx_read "struct agentx *sa"
+.Ft void
+.Fn agentx_write "struct agentx *sa"
+.Ft extern void
+.Fn (*agentx_wantwrite) "struct agentx *sa" "int fd"
+.Ft void
+.Fn agentx_free "struct agentx *sa"
+.Ft struct agentx_session *
+.Fo agentx_session
+.Fa "struct agentx *sa" "uint32_t oid[]" "size_t oidlen"
+.Fa "const char *descr" "uint8_t timeout"
+.Fc
+.Ft void
+.Fn agentx_session_free "struct agentx_session *sas"
+.Ft struct agentx_context *
+.Fn agentx_context "struct agentx_session *sas" "const char *name"
+.Ft struct agentx_object *
+.Fo agentx_context_object_find
+.Fa "struct agentx_context *sac" "const uint32_t oid[]" "size_t oidlen"
+.Fa "int active" "int instance"
+.Fc
+.Ft struct agentx_object *
+.Fo agentx_context_object_nfind
+.Fa "struct agentx_context *" "const uint32_t oid[]" "size_t oidlen"
+.Fa "int active" "int inclusive"
+.Fc
+.Ft uint32_t
+.Fn agentx_context_uptime "struct agentx_context *sac"
+.Ft void
+.Fn agentx_context_free "struct agentx_context *sac"
+.Ft struct agentx_agentcaps *
+.Fo agentx_agentcaps
+.Fa "struct agentx_context *sac" "uint32_t oid[]" "size_t oidlen"
+.Fa "const char *descr"
+.Fc
+.Ft void
+.Fn agentx_agentcaps_free "struct agentx_agentcaps *saa"
+.Ft struct agentx_region *
+.Fo agentx_region
+.Fa "struct agentx_context *sac" "uint32_t oid[]"
+.Fa "size_t oidlen" "uint8_t timeout"
+.Fc
+.Ft void
+.Fn agentx_region_free "struct agentx_region *sar"
+.Ft struct agentx_index *
+.Fo agentx_index_integer_new
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_integer_any
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_integer_value
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fa "uint32_t value"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_integer_dynamic
+.Fa "struct agentx_region *sar" "uint32_t oid[] "size_t oidlen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_string_dynamic
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_nstring_dynamic
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fa "size_t slen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_oid_dynamic
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_noid_dynamic
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fa "size_t vlen"
+.Fc
+.Ft struct agentx_index *
+.Fo agentx_index_ipaddress_dynamic
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fc
+.Ft void
+.Fn agentx_index_free "struct agentx_index *sai"
+.Ft struct agentx_object *
+.Fo agentx_object
+.Fa "struct agentx_region *sar" "uint32_t oid[]" "size_t oidlen"
+.Fa "struct agentx_index *index[]" "size_t indexlen" "int implied"
+.Fa "void (*getcb)(struct agentx_varbind *)"
+.Fc
+.Ft void
+.Fn agentx_object_free "struct agentx_object *sao"
+.Ft void
+.Fn agentx_varbind_integer "struct agentx_varbind *sav" "uint32_t value"
+.Ft void
+.Fn agentx_varbind_string "struct agentx_varbind *sav" "const char *value"
+.Ft void
+.Fo agentx_varbind_nstring
+.Fa "struct agentx_varbind *sav" "const char *value" "size_t slen"
+.Fc
+.Ft void
+.Fo agentx_varbind_printf
+.Fa "struct agentx_varbind *sav" "const char *fmt" ...
+.Fc
+.Ft void
+.Fn agentx_varbind_null "struct agentx_varbind *sav"
+.Ft void
+.Fo agentx_varbind_oid
+.Fa "struct agentx_varbind *sav" "const uint32_t oid[]" "size_t oidlen"
+.Fc
+.Ft void
+.Fo agentx_varbind_object
+.Fa "struct agentx_varbind *sav" "struct agentx_object *sao"
+.Fc
+.Ft void
+.Fo agentx_varbind_index
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fc
+.Ft void
+.Fo agentx_varbind_ipaddress
+.Fa "struct agentx_varbind *sav" "const struct in_addr *addr"
+.Fc
+.Ft void
+.Fn agentx_varbind_counter32 "struct agentx_varbind *sav" "uint32_t value"
+.Ft void
+.Fn agentx_varbind_gauge32 "struct agentx_varbind *sav" "uint32_t value"
+.Ft void
+.Fo agentx_varbind_timeticks
+.Fa "struct agentx_varbind *sav" "uint32_t value"
+.Fc
+.Ft void
+.Fo agentx_varbind_opaque
+.Fa "struct agentx_varbind *sav" "const char *value" "size_t slen"
+.Fc
+.Ft void
+.Fn agentx_varbind_counter64 "struct agentx_varbind *sav" "uint64_t value"
+.Ft void
+.Fn agentx_varbind_notfound "struct agentx_varbind *sav"
+.Ft void
+.Fn agentx_varbind_error "struct agentx_varbind *sav"
+.Ft enum agentx_request_type
+.Fn agentx_varbind_request "struct agentx_varbind *sav"
+.Ft uint32_t
+.Fo agentx_varbind_get_index_integer
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fc
+.Ft const unsigned char *
+.Fo agentx_varbind_get_index_string
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai" "size_t *slen"
+.Fa "int *implied"
+.Fc
+.Ft const uint32_t *
+.Fo agentx_varbind_get_index_oid
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "size_t *oidlen" "int *implied"
+.Fc
+.Ft const struct in_addr *
+.Fo agentx_varbind_get_index_ipaddress
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fc
+.Ft void
+.Fo agentx_varbind_set_index_integer
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "uint32_t value"
+.Fc
+.Ft void
+.Fo agentx_varbind_set_index_string
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "const unsigned char *value"
+.Fc
+.Ft void
+.Fo agentx_varbind_set_index_nstring
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "const unsigned char *value" "size_t slen"
+.Fc
+.Ft void
+.Fo agentx_varbind_set_index_oid
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "const uint32_t *oid" "size_t oidlen"
+.Fc
+.Ft void
+.Fo agentx_varbind_set_index_object
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "struct agentx_object *sao"
+.Fc
+.Ft void
+.Fo agentx_varbind_set_index_ipaddress
+.Fa "struct agentx_varbind *sav" "struct agentx_index *sai"
+.Fa "const struct in_addr *addr"
+.Fc
+.Bd -literal
+enum agentx_request_type {
+ AGENTX_REQUEST_TYPE_GET,
+ AGENTX_REQUEST_TYPE_GETNEXT,
+ AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
+};
+.Ed
+.Fd #define AGENTX_MASTER_PATH \(dq/var/agentx/master\(dq
+.Fd #define AGENTX_OID_MAX_LEN 128
+.Fd #define AGENTX_OID_INDEX_MAX_LEN 10
+.Fd #define AGENTX_OID(...)
+.Fd #define AGENTX_MIB2 1, 3, 6, 1, 2, 1
+.Fd #define AGENTX_ENTERPRISES 1, 3, 6, 1, 4, 1
+.Sh DESCRIPTION
+The
+.Nm agentx
+functions allow an application to describe their MIB layout and provide an
+.Fa fd
+based interface to control the internal agentx state.
+.Nm agentx
+is not thread safe.
+.Ss DESCRIBING THE MIB
+.Nm agentx
+is a framework to abstract away the agentx protocol from the application.
+For the framework to report information to the administrator, the
+.Fn agentx_log_fatal ,
+.Fn agentx_log_warn ,
+.Fn agentx_log_info
+and
+.Fn agentx_log_debug
+functions must be set.
+.Pp
+When
+.Fa sa
+is created by
+.Fn agentx
+or when
+.Fa sa
+detects that there is no connection to the agentx master it calls out to
+.Fa nofd
+with itself,
+.Fa cookie
+and an integer
+.Fa close
+as arguments.
+If
+.Fa close
+is not set
+.Fn nofd
+is expected to set up a new
+.Fa fd
+to the agentx master.
+This one can usually be found at
+.Dv AGENTX_MASTER_PATH .
+This
+.Fa fd
+can be returned to
+.Fa sa
+at any moment via
+.Fn agentx_connect ,
+but must always be done as a result of a call to
+.Fn nofd .
+Once
+.Fn agentx_connect
+has been called the application is responsible for retrieving data when available
+on
+.Fa fd
+by calling
+.Fn agentx_read .
+If nonblocking writes are desirable the
+.Fn agentx_wantwrite
+pointer can be set to an application function and will be called as soon as
+there's data available to be written out.
+Once
+.Fa fd
+is ready for write the function
+.Fn agentx_write
+should be called.
+.Pp
+.Fa sa
+can be freed via
+.Fn agentx_free .
+It will close all active sessions and free all derived objects.
+Once freed no new objects can be derived from the freed objects.
+Once all sessions are closed it will call out to
+.Fn nofd
+with
+.Fa close
+set, indicating that the application can clean up any context related to
+.Fa sa .
+.Pp
+On top of the
+.Fa sa
+connection a
+.Vt agentx_session
+must be set up.
+Normally there's only a single session per
+.Fa sa .
+The
+.Fa timeout
+argument specifies the maximum time in seconds the master should wait for a
+reply before determining we're gone.
+If set to 0 the agentx master determines the timeout.
+The
+.Fa oid
+and
+.Fa oidlen
+combination identifies the subagent and will be visible through the
+agentxSessionObjectID object on the agentx master.
+The
+.Fa descr
+is a short displaystring description of the agent and will be visiable through
+the agentxSessionDescr object on the agentx master.
+.Pp
+The
+.Vt agentx_context
+is the SNMPv3 context in which the objects operate and is built on top of
+agentx_session
+.Fa sas .
+If the default context is requested
+.Fa name
+must be NULL.
+.Pp
+.Fn agentx_agentcaps
+registers an entry in the agentx master's sysORTable.
+The
+.Fa oid ,
+.Fa oidlen
+combination should point to an AGENT-CAPABILITIES object which describes the
+capabilities of the subagent.
+.Fa descr
+should be a textual description of the capabilities.
+If no AGENT-CAPABILITIES object is defined this function can be omitted.
+.Pp
+A
+.Vt agentx_region
+indicates a region inside the object-tree for which get- and set-requests will
+be queried.
+If the OID has already been claimed by another subagent it will try to claim it
+on a lower priority.
+The
+.Fa timeout
+parameter overrules its
+.Vt agentx_session
+counterpart.
+.Pp
+For objects in a table one or more
+.Ft agentx_index
+elements must be supplied.
+.Fn agentx_index_integer_new ,
+.Fn agentx_index_integer_any
+and
+.Fn agentx_index_integer_value
+register an integer index at the agentx master.
+Of these
+.Fn agentx_index_integer_new
+registers a new, previously unused, index;
+.Fn agentx_index_integer_any
+registers the first available index;
+and
+.Fn agentx_index_integer_value
+tries to register a specific value.
+If the registration of an index fails an error will be logged and all objects
+using it will remain disabled.
+The OID where the index should be registered is documented by the MIB.
+These registered indices are usually used for tables where multiple subagents
+are registered.
+.Pp
+For dynamic indices the agentx_index_*_dynamic functions can be used, based
+on the data type of the object.
+The data type should match the data type in the MIB at the
+.Fa oid
+object.
+Indices of data type string or oid with a fixed length should be created via
+.Fn agentx_index_nstring_dynamic
+and
+.Fn agentx_index_noid_dynamic
+respectively.
+.Pp
+.Vt agentx_object
+is an object as described in the MIB.
+For scalar objects
+.Pq without indices
+the final zero must be omitted.
+For table entries a list of 1 or more indices must be added via
+.Fa index
+and
+.Fa indexlen .
+The list of indices must match the INDEX list on the ENTRY object in the MIB.
+The total length of the OID, including indices, can't be more than
+.Dv AGENTX_OID_MAX_LEN
+and indexlen can't be more than
+.Dv AGENTX_OID_INDEX_MAX_LEN .
+If
+.Fa implied
+is set the final index must be of type OID or string and will omit the leading
+length indicator.
+This value must only be set if specified in the MIB.
+.Fn getcb
+will be called for each varbind in a GET, GETNEXT or GETBULK request that
+matches the object.
+.Ss HANDLING GET REQUESTS
+A call to
+.Fn getcb
+must eventually result in a call to one of the following functions:
+.Bl -tag -width agentx_varbind_counter32()
+.It Fn agentx_varbind_integer
+Set the return value to an uint32_t value.
+.It Fn agentx_varbind_string
+A C string wrapper around
+.Fn agentx_varbind_nstring .
+.It Fn agentx_varbind_nstring
+Set the return value to an octetstring.
+.It Fn agentx_varbind_printf
+A printf wrapper around
+.Fn agentx_varbind_nstring .
+.It Fn agentx_varbind_null
+Set the return value to null.
+.It Fn agentx_varbind_oid
+Set the return value to an OID value.
+.It Fn agentx_varbind_object
+An agentx_object wrapper around
+.Fn agentx_varbind_oid .
+.It Fn agentx_varbind_index
+An agentx_index wrapper around
+.Fn agentx_varbind_oid .
+.It Fn agentx_varbind_ipaddress
+Set the return value to ipaddress.
+.It Fn agentx_varbind_counter32
+Set the return value to an uint32_t of type counter32.
+.It Fn agentx_varbind_gauge32
+Set the return value to an uint32_t of type gauge32.
+.It Fn agentx_varbind_timeticks
+Set the return value to an uint32_t of type timeticks.
+.It Fn agentx_varbind_opaque
+Set the return value to an opaque value.
+.It Fn agentx_varbind_counter64
+Set the return value to an uint64_t of type counter64.
+.It Fn agentx_varbind_notfound
+When the request is of type GET return an nosuchinstance error.
+When the request is of type GETNEXT or GETBULK return an endofmibview error.
+On endofmibview the next object is queried.
+This function can only be called on objects that contain one or more *_dynamic
+indices.
+.It Fn agentx_varbind_error
+Returns a GENERR error to the client.
+.El
+.Pp
+For objects containing *_dynamic indices the following support functions are to
+be used:
+.Bl -tag -width Ds
+.It Fn agentx_varbind_request
+Returns whether the request is of type GET, GETNEXT or GETNEXTINCLUSIVE.
+.It Fn agentx_varbind_get_index_integer
+Retrieve a single uint32_t index value.
+.It Fn agentx_varbind_get_index_string
+Retrieve an octetstring index value.
+.Fa slen
+is the length of the string and
+.Fa implied
+indicates if the next value for this index should be length sorted before
+alphabetically sorted.
+.It Fn agentx_varbind_get_index_oid
+Retrieve an oid index value.
+.Fa oidlen
+is the length of the oid and
+.Fa implied
+indicates if the next value for this index should be length sorted before
+alphabetically sorted.
+.It Fn agentx_varbind_get_index_ipaddress
+Retrieve an ipaddress index value.
+.It Fn agentx_varbind_set_index_integer
+Sets a single uint32_t index value.
+.It Fn agentx_varbind_set_index_string
+A C string wrapper around
+.Fn agentx_varbind_set_index_nstring .
+.It Fn agentx_varbind_set_index_nstring
+Set an octetstring index value.
+.It Fn agentx_varbind_set_index_oid
+Set an oid index value.
+.It Fn agentx_varbind_set_index_object
+A agentx_object wrapper around
+.Fn agentx_varbind_set_index_oid .
+.It Fn agentx_varbind_set_index_ipaddress
+Set an ipaddress index value.
+.El
+.Pp
+For these functions
+.Fa sai
+must be part of the object the request is performed on.
+The function type must also match the data type of
+.Fa sai .
+.Pp
+Other functions that can retrieve information from the agentx context are:
+.Bl -tag -width Ds
+.It Fn agentx_context_object_find
+Find a agentx_object created inside agentx_context
+.Fa sac
+based on
+.Fa oid
+and
+.Fa oidlen .
+If
+.Fa active
+is set the object must be reachable from the agentx master, else NULL is
+returned.
+If
+.Fa oid
+can be an instance, find its parent object.
+.It Fn agentx_context_object_nfind
+Find the next agentx_object created inside agentx_context
+.Fa sac
+based on
+.Fa oid
+and
+.Fa oidlen .
+If
+.Fa active
+is set the object must be reachable from the agentx master, else NULL is
+returned.
+If
+.Fa inclusive
+is set the object returned may also exactly match
+.Fa oid .
+.It Fn agentx_context_uptime
+Returns the sysuptime in seconds for
+.Fa sac
+in timeticks.
+.El
+.Sh SEE ALSO
+.Xr snmp 1 ,
+.Xr snmpd 8
+.Sh STANDARDS
+.Rs
+.%A M. Daniele
+.%A B. Wijnen
+.%A M. Ellison, Ed.
+.%A D. Francisco, Ed.
+.%D January 2000
+.%R RFC 2741
+.%T Agent Extensibility (AgentX) Protocol Version 1
+.Re
+.Pp
+.Rs
+.%A L. Heintz
+.%A S. Gudur
+.%A M. Ellison, Ed.
+.%D January 2000
+.%R RFC 2742
+.%T Definitions of Managed Objects for Extensible SNMP Agents
+.Re
+.Sh HISTORY
+The
+.Nm agentx
+API first appeared in
+.Ox 6.8 .
+.Sh AUTHORS
+.An Martijn van Duren Aq Mt martijn@openbsd.org
diff --git a/lib/libagentx/agentx.c b/lib/libagentx/agentx.c
index 2e70a502f8a..6cafec2a04d 100644
--- a/lib/libagentx/agentx.c
+++ b/lib/libagentx/agentx.c
@@ -13,1347 +13,3991 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/socket.h>
+#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <ctype.h>
-#include <endian.h>
#include <errno.h>
-#include <inttypes.h>
+#include <stdarg.h>
#include <stdlib.h>
-#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
+#include <time.h>
#include <unistd.h>
+#include "agentx_internal.h"
#include "agentx.h"
-#define AGENTX_PDU_HEADER 20
-
-static int agentx_pdu_need(struct agentx *, size_t);
-static int agentx_pdu_header(struct agentx *,
- enum agentx_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t,
- struct agentx_ostring *);
-static uint32_t agentx_packetid(struct agentx *);
-static uint32_t agentx_pdu_queue(struct agentx *);
-static int agentx_pdu_add_uint16(struct agentx *, uint16_t);
-static int agentx_pdu_add_uint32(struct agentx *, uint32_t);
-static int agentx_pdu_add_uint64(struct agentx *, uint64_t);
-static int agentx_pdu_add_oid(struct agentx *, struct agentx_oid *, int);
-static int agentx_pdu_add_str(struct agentx *, struct agentx_ostring *);
-static int agentx_pdu_add_varbindlist( struct agentx *, struct agentx_varbind *,
- size_t);
-static uint16_t agentx_pdutoh16(struct agentx_pdu_header *, uint8_t *);
-static uint32_t agentx_pdutoh32(struct agentx_pdu_header *, uint8_t *);
-static uint64_t agentx_pdutoh64(struct agentx_pdu_header *, uint8_t *);
-static ssize_t agentx_pdutooid(struct agentx_pdu_header *, struct agentx_oid *,
- uint8_t *, size_t);
-static ssize_t agentx_pdutoostring(struct agentx_pdu_header *,
- struct agentx_ostring *, uint8_t *, size_t);
-static ssize_t agentx_pdutovarbind(struct agentx_pdu_header *,
- struct agentx_varbind *, uint8_t *, size_t);
+enum agentx_index_type {
+ AXI_TYPE_NEW,
+ AXI_TYPE_ANY,
+ AXI_TYPE_VALUE,
+ AXI_TYPE_DYNAMIC
+};
+
+#define AGENTX_CONTEXT_CTX(axc) (axc->axc_name_default ? NULL : \
+ &(axc->axc_name))
+
+struct agentx_agentcaps {
+ struct agentx_context *axa_axc;
+ struct ax_oid axa_oid;
+ struct ax_ostring axa_descr;
+ enum agentx_cstate axa_cstate;
+ enum agentx_dstate axa_dstate;
+ TAILQ_ENTRY(agentx_agentcaps) axa_axc_agentcaps;
+};
+
+struct agentx_region {
+ struct agentx_context *axr_axc;
+ struct ax_oid axr_oid;
+ uint8_t axr_timeout;
+ uint8_t axr_priority;
+ enum agentx_cstate axr_cstate;
+ enum agentx_dstate axr_dstate;
+ TAILQ_HEAD(, agentx_index) axr_indices;
+ TAILQ_HEAD(, agentx_object) axr_objects;
+ TAILQ_ENTRY(agentx_region) axr_axc_regions;
+};
+
+struct agentx_index {
+ struct agentx_region *axi_axr;
+ enum agentx_index_type axi_type;
+ struct ax_varbind axi_vb;
+ struct agentx_object **axi_object;
+ size_t axi_objectlen;
+ size_t axi_objectsize;
+ enum agentx_cstate axi_cstate;
+ enum agentx_dstate axi_dstate;
+ TAILQ_ENTRY(agentx_index) axi_axr_indices;
+};
+
+struct agentx_object {
+ struct agentx_region *axo_axr;
+ struct ax_oid axo_oid;
+ struct agentx_index *axo_index[AGENTX_OID_INDEX_MAX_LEN];
+ size_t axo_indexlen;
+ int axo_implied;
+ uint8_t axo_timeout;
+ /* Prevent freeing object while in use by get and set requesets */
+ uint32_t axo_lock;
+ void (*axo_get)(struct agentx_varbind *);
+ enum agentx_cstate axo_cstate;
+ enum agentx_dstate axo_dstate;
+ RB_ENTRY(agentx_object) axo_axc_objects;
+ TAILQ_ENTRY(agentx_object) axo_axr_objects;
+};
+
+struct agentx_varbind {
+ struct agentx_get *axv_axg;
+ struct agentx_object *axv_axo;
+ struct agentx_varbind_index {
+ struct agentx_index *axv_axi;
+ union ax_data axv_idata;
+ uint8_t axv_idatacomplete;
+ } axv_index[AGENTX_OID_INDEX_MAX_LEN];
+ size_t axv_indexlen;
+ int axv_initialized;
+ int axv_include;
+ struct ax_varbind axv_vb;
+ struct ax_oid axv_start;
+ struct ax_oid axv_end;
+ enum ax_pdu_error axv_error;
+};
+
+#define AGENTX_GET_CTX(axg) (axg->axg_context_default ? NULL : \
+ &(axg->axg_context))
+struct agentx_request {
+ uint32_t axr_packetid;
+ int (*axr_cb)(struct ax_pdu *, void *);
+ void *axr_cookie;
+ RB_ENTRY(agentx_request) axr_ax_requests;
+};
+
+static void agentx_start(struct agentx *);
+static void agentx_finalize(struct agentx *, int);
+static void agentx_wantwritenow(struct agentx *, int);
+void (*agentx_wantwrite)(struct agentx *, int) =
+ agentx_wantwritenow;
+static void agentx_reset(struct agentx *);
+static void agentx_free_finalize(struct agentx *);
+static int agentx_session_start(struct agentx_session *);
+static int agentx_session_finalize(struct ax_pdu *, void *);
+static int agentx_session_close(struct agentx_session *,
+ enum ax_close_reason);
+static int agentx_session_close_finalize(struct ax_pdu *, void *);
+static void agentx_session_free_finalize(struct agentx_session *);
+static void agentx_session_reset(struct agentx_session *);
+static void agentx_context_start(struct agentx_context *);
+static void agentx_context_free_finalize(struct agentx_context *);
+static void agentx_context_reset(struct agentx_context *);
+static int agentx_agentcaps_start(struct agentx_agentcaps *);
+static int agentx_agentcaps_finalize(struct ax_pdu *, void *);
+static int agentx_agentcaps_close(struct agentx_agentcaps *);
+static int agentx_agentcaps_close_finalize(struct ax_pdu *, void *);
+static void agentx_agentcaps_free_finalize(struct agentx_agentcaps *);
+static void agentx_agentcaps_reset(struct agentx_agentcaps *);
+static int agentx_region_start(struct agentx_region *);
+static int agentx_region_finalize(struct ax_pdu *, void *);
+static int agentx_region_close(struct agentx_region *);
+static int agentx_region_close_finalize(struct ax_pdu *, void *);
+static void agentx_region_free_finalize(struct agentx_region *);
+static void agentx_region_reset(struct agentx_region *);
+static struct agentx_index *agentx_index(struct agentx_region *,
+ struct ax_varbind *, enum agentx_index_type);
+static int agentx_index_start(struct agentx_index *);
+static int agentx_index_finalize(struct ax_pdu *, void *);
+static void agentx_index_free_finalize(struct agentx_index *);
+static void agentx_index_reset(struct agentx_index *);
+static int agentx_index_close(struct agentx_index *);
+static int agentx_index_close_finalize(struct ax_pdu *, void *);
+static int agentx_object_start(struct agentx_object *);
+static int agentx_object_finalize(struct ax_pdu *, void *);
+static int agentx_object_lock(struct agentx_object *);
+static void agentx_object_unlock(struct agentx_object *);
+static int agentx_object_close(struct agentx_object *);
+static int agentx_object_close_finalize(struct ax_pdu *, void *);
+static void agentx_object_free_finalize(struct agentx_object *);
+static void agentx_object_reset(struct agentx_object *);
+static int agentx_object_cmp(struct agentx_object *,
+ struct agentx_object *);
+static void agentx_get_start(struct agentx_context *,
+ struct ax_pdu *);
+static void agentx_get_finalize(struct agentx_get *);
+static void agentx_get_free(struct agentx_get *);
+static void agentx_varbind_start(struct agentx_varbind *);
+static void agentx_varbind_finalize(struct agentx_varbind *);
+static void agentx_varbind_nosuchobject(struct agentx_varbind *);
+static void agentx_varbind_nosuchinstance(struct agentx_varbind *);
+static void agentx_varbind_endofmibview(struct agentx_varbind *);
+static void agentx_varbind_error_type(struct agentx_varbind *,
+ enum ax_pdu_error, int);
+static int agentx_request(struct agentx *, uint32_t,
+ int (*)(struct ax_pdu *, void *), void *);
+static int agentx_request_cmp(struct agentx_request *,
+ struct agentx_request *);
+static int agentx_strcat(char **, const char *);
+
+RB_PROTOTYPE_STATIC(ax_requests, agentx_request, axr_ax_requests,
+ agentx_request_cmp)
+RB_PROTOTYPE_STATIC(axc_objects, agentx_object, axo_axc_objects,
+ agentx_object_cmp)
struct agentx *
-agentx_new(int fd)
+agentx(void (*nofd)(struct agentx *, void *, int), void *cookie)
{
struct agentx *ax;
- if (fd == -1) {
- errno = EINVAL;
+ if ((ax = calloc(1, sizeof(*ax))) == NULL)
return NULL;
+
+ ax->ax_nofd = nofd;
+ ax->ax_cookie = cookie;
+ ax->ax_fd = -1;
+ ax->ax_cstate = AX_CSTATE_CLOSE;
+ ax->ax_dstate = AX_DSTATE_OPEN;
+ TAILQ_INIT(&(ax->ax_sessions));
+ TAILQ_INIT(&(ax->ax_getreqs));
+ RB_INIT(&(ax->ax_requests));
+
+ agentx_start(ax);
+
+ return ax;
+}
+
+/*
+ * agentx_finalize is not a suitable name for a public API,
+ * but use it internally for consistency
+ */
+void
+agentx_connect(struct agentx *ax, int fd)
+{
+ agentx_finalize(ax, fd);
+}
+
+static void
+agentx_start(struct agentx *ax)
+{
+#ifdef AX_DEBUG
+ if (ax->ax_cstate != AX_CSTATE_CLOSE ||
+ ax->ax_dstate != AX_DSTATE_OPEN)
+ agentx_log_ax_fatalx(ax, "%s: unexpected connect", __func__);
+#endif
+ ax->ax_cstate = AX_CSTATE_WAITOPEN;
+ ax->ax_nofd(ax, ax->ax_cookie, 0);
+}
+
+static void
+agentx_finalize(struct agentx *ax, int fd)
+{
+ struct agentx_session *axs;
+
+ if (ax->ax_cstate != AX_CSTATE_WAITOPEN) {
+#ifdef AX_DEBUG
+ agentx_log_ax_fatalx(ax, "%s: agentx unexpected connect",
+ __func__);
+#else
+ agentx_log_ax_warnx(ax,
+ "%s: agentx unexpected connect: ignoring", __func__);
+ return;
+#endif
+ }
+ if ((ax->ax_ax = ax_new(fd)) == NULL) {
+ agentx_log_ax_warn(ax, "failed to initialize");
+ close(fd);
+ agentx_reset(ax);
+ return;
}
- if ((ax = calloc(1, sizeof(*ax))) == NULL)
- return NULL;
+ agentx_log_ax_info(ax, "new connection: %d", fd);
+
ax->ax_fd = fd;
- if ((ax->ax_rbuf = malloc(512)) == NULL)
- goto fail;
- ax->ax_rbsize = 512;
- ax->ax_byteorder = AGENTX_BYTE_ORDER_NATIVE;
+ ax->ax_cstate = AX_CSTATE_OPEN;
- return ax;
+ TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
+ if (agentx_session_start(axs) == -1)
+ break;
+ }
+}
-fail:
- free(ax);
- return NULL;
+static void
+agentx_wantwritenow(struct agentx *ax, int fd)
+{
+ agentx_write(ax);
+}
+
+static void
+agentx_reset(struct agentx *ax)
+{
+ struct agentx_session *axs, *tsas;
+ struct agentx_request *axr;
+ struct agentx_get *axg;
+
+ ax_free(ax->ax_ax);
+ ax->ax_ax = NULL;
+ ax->ax_fd = -1;
+
+ ax->ax_cstate = AX_CSTATE_CLOSE;
+
+ while ((axr = RB_MIN(ax_requests, &(ax->ax_requests))) != NULL) {
+ RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
+ free(axr);
+ }
+ TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, tsas)
+ agentx_session_reset(axs);
+ while (!TAILQ_EMPTY(&(ax->ax_getreqs))) {
+ axg = TAILQ_FIRST(&(ax->ax_getreqs));
+ axg->axg_axc = NULL;
+ TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
+ }
+
+ if (ax->ax_dstate == AX_DSTATE_CLOSE) {
+ agentx_free_finalize(ax);
+ return;
+ }
+
+ agentx_start(ax);
}
void
agentx_free(struct agentx *ax)
{
+ struct agentx_session *axs, *tsas;
+
if (ax == NULL)
return;
- close(ax->ax_fd);
- free(ax->ax_rbuf);
- free(ax->ax_wbuf);
- free(ax->ax_packetids);
+
+ if (ax->ax_dstate == AX_DSTATE_CLOSE) {
+/* Malloc throws abort on invalid pointers as well */
+ agentx_log_ax_fatalx(ax, "%s: double free", __func__);
+ }
+ ax->ax_dstate = AX_DSTATE_CLOSE;
+
+ if (!TAILQ_EMPTY(&(ax->ax_sessions))) {
+ TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions,
+ tsas) {
+ if (axs->axs_dstate != AX_DSTATE_CLOSE)
+ agentx_session_free(axs);
+ }
+ } else
+ agentx_free_finalize(ax);
+}
+
+static void
+agentx_free_finalize(struct agentx *ax)
+{
+#ifdef AX_DEBUG
+ if (ax->ax_dstate != AX_DSTATE_CLOSE)
+ agentx_log_ax_fatalx(ax, "%s: agentx not closing",
+ __func__);
+ if (!TAILQ_EMPTY(&(ax->ax_sessions)))
+ agentx_log_ax_fatalx(ax, "%s: agentx still has sessions",
+ __func__);
+ if (!RB_EMPTY(&(ax->ax_requests)))
+ agentx_log_ax_fatalx(ax,
+ "%s: agentx still has pending requests", __func__);
+#endif
+
+ ax_free(ax->ax_ax);
+ ax->ax_nofd(ax, ax->ax_cookie, 1);
free(ax);
}
-struct agentx_pdu *
-agentx_recv(struct agentx *ax)
-{
- struct agentx_pdu *pdu;
- struct agentx_pdu_header header;
- struct agentx_pdu_response *response;
- struct agentx_varbind *varbind;
- struct agentx_pdu_searchrangelist *srl = NULL;
- struct agentx_pdu_varbindlist *vbl;
- struct agentx_searchrange *sr;
- size_t rbsize, packetidx = 0, i, rawlen;
- ssize_t nread;
- uint8_t *u8;
- uint8_t *rbuf;
- int found;
+struct agentx_session *
+agentx_session(struct agentx *ax, uint32_t oid[],
+ size_t oidlen, const char *descr, uint8_t timeout)
+{
+ struct agentx_session *axs;
+ size_t i;
- /* Only read a single packet at a time to make sure libevent triggers */
- if (ax->ax_rblen < AGENTX_PDU_HEADER) {
- if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
- AGENTX_PDU_HEADER - ax->ax_rblen)) == 0) {
- errno = ECONNRESET;
- return NULL;
- }
- if (nread == -1)
- return NULL;
- ax->ax_rblen += nread;
- if (ax->ax_rblen < AGENTX_PDU_HEADER) {
- errno = EAGAIN;
- return NULL;
- }
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_ax_fatalx(ax, "%s: oidlen > %d", __func__,
+ AGENTX_OID_MAX_LEN);
+#else
+ errno = EINVAL;
+ return NULL;
+#endif
}
- u8 = ax->ax_rbuf;
- header.aph_version = *u8++;
- header.aph_type = *u8++;
- header.aph_flags = *u8++;
- u8++;
- header.aph_sessionid = agentx_pdutoh32(&header, u8);
- u8 += 4;
- header.aph_transactionid = agentx_pdutoh32(&header, u8);
- u8 += 4;
- header.aph_packetid = agentx_pdutoh32(&header, u8);
- u8 += 4;
- header.aph_plength = agentx_pdutoh32(&header, u8);
-
- if (header.aph_version != 1) {
- errno = EPROTO;
+ if ((axs = calloc(1, sizeof(*axs))) == NULL)
+ return NULL;
+
+ axs->axs_ax = ax;
+ axs->axs_timeout = timeout;
+ for (i = 0; i < oidlen; i++)
+ axs->axs_oid.aoi_id[i] = oid[i];
+ axs->axs_oid.aoi_idlen = oidlen;
+ axs->axs_descr.aos_string = (unsigned char *)strdup(descr);
+ if (axs->axs_descr.aos_string == NULL) {
+ free(axs);
return NULL;
}
- if (ax->ax_rblen < AGENTX_PDU_HEADER + header.aph_plength) {
- if (AGENTX_PDU_HEADER + header.aph_plength > ax->ax_rbsize) {
- rbsize = (((AGENTX_PDU_HEADER + header.aph_plength)
- / 512) + 1) * 512;
- if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize,
- rbsize, sizeof(*rbuf))) == NULL)
- return NULL;
- ax->ax_rbsize = rbsize;
- ax->ax_rbuf = rbuf;
- }
- nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
- header.aph_plength - (ax->ax_rblen - AGENTX_PDU_HEADER));
- if (nread == 0)
- errno = ECONNRESET;
- if (nread <= 0)
- return NULL;
- ax->ax_rblen += nread;
- if (ax->ax_rblen < AGENTX_PDU_HEADER + header.aph_plength) {
- errno = EAGAIN;
+ axs->axs_descr.aos_slen = strlen(descr);
+ axs->axs_cstate = AX_CSTATE_CLOSE;
+ axs->axs_dstate = AX_DSTATE_OPEN;
+ TAILQ_INIT(&(axs->axs_contexts));
+ TAILQ_INSERT_HEAD(&(ax->ax_sessions), axs, axs_ax_sessions);
+
+ if (ax->ax_cstate == AX_CSTATE_OPEN)
+ (void) agentx_session_start(axs);
+
+ return axs;
+}
+
+static int
+agentx_session_start(struct agentx_session *axs)
+{
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (ax->ax_cstate != AX_CSTATE_OPEN ||
+ axs->axs_cstate != AX_CSTATE_CLOSE ||
+ axs->axs_dstate != AX_DSTATE_OPEN)
+ agentx_log_ax_fatalx(ax, "%s: unexpected session open",
+ __func__);
+#endif
+ packetid = ax_open(ax->ax_ax, axs->axs_timeout, &(axs->axs_oid),
+ &(axs->axs_descr));
+ if (packetid == 0) {
+ agentx_log_ax_warn(ax, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_OPEN));
+ agentx_reset(ax);
+ return -1;
+ }
+ axs->axs_packetid = packetid;
+ agentx_log_ax_info(ax, "opening session");
+ axs->axs_cstate = AX_CSTATE_WAITOPEN;
+ return agentx_request(ax, packetid, agentx_session_finalize, axs);
+}
+
+static int
+agentx_session_finalize(struct ax_pdu *pdu, void *cookie)
+{
+ struct agentx_session *axs = cookie;
+ struct agentx *ax = axs->axs_ax;
+ struct agentx_context *axc;
+
+#ifdef AX_DEBUG
+ if (axs->axs_cstate != AX_CSTATE_WAITOPEN)
+ agentx_log_ax_fatalx(ax, "%s: not expecting new session",
+ __func__);
+#endif
+
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ agentx_log_ax_warnx(ax, "failed to open session: %s",
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ agentx_reset(ax);
+ return -1;
+ }
+
+ axs->axs_id = pdu->ap_header.aph_sessionid;
+ axs->axs_cstate = AX_CSTATE_OPEN;
+
+ if (axs->axs_dstate == AX_DSTATE_CLOSE) {
+ agentx_session_close(axs, AX_CLOSE_SHUTDOWN);
+ return 0;
+ }
+
+ agentx_log_axs_info(axs, "open");
+
+ TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts)
+ agentx_context_start(axc);
+ return 0;
+}
+
+static int
+agentx_session_close(struct agentx_session *axs,
+ enum ax_close_reason reason)
+{
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (axs->axs_cstate != AX_CSTATE_OPEN)
+ agentx_log_ax_fatalx(ax, "%s: unexpected session close",
+ __func__);
+#endif
+ if ((packetid = ax_close(ax->ax_ax, axs->axs_id, reason)) == 0) {
+ agentx_log_axs_warn(axs, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_CLOSE));
+ agentx_reset(ax);
+ return -1;
+ }
+
+ agentx_log_axs_info(axs, "closing session: %s",
+ ax_closereason2string(reason));
+
+ axs->axs_cstate = AX_CSTATE_WAITCLOSE;
+ return agentx_request(ax, packetid, agentx_session_close_finalize,
+ axs);
+}
+
+static int
+agentx_session_close_finalize(struct ax_pdu *pdu, void *cookie)
+{
+ struct agentx_session *axs = cookie;
+ struct agentx *ax = axs->axs_ax;
+ struct agentx_context *axc, *tsac;
+
+#ifdef AX_DEBUG
+ if (axs->axs_cstate != AX_CSTATE_WAITCLOSE)
+ agentx_log_axs_fatalx(axs, "%s: not expecting session close",
+ __func__);
+#endif
+
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ agentx_log_axs_warnx(axs, "failed to close session: %s",
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ agentx_reset(ax);
+ return -1;
+ }
+
+ axs->axs_cstate = AX_CSTATE_CLOSE;
+
+ agentx_log_axs_info(axs, "closed");
+
+ TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, tsac)
+ agentx_context_reset(axc);
+
+ if (axs->axs_dstate == AX_DSTATE_CLOSE)
+ agentx_session_free_finalize(axs);
+ else {
+ if (ax->ax_cstate == AX_CSTATE_OPEN)
+ if (agentx_session_start(axs) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+void
+agentx_session_free(struct agentx_session *axs)
+{
+ struct agentx_context *axc, *tsac;
+
+ if (axs == NULL)
+ return;
+
+ if (axs->axs_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axs_fatalx(axs, "%s: double free", __func__);
+
+ axs->axs_dstate = AX_DSTATE_CLOSE;
+
+ if (axs->axs_cstate == AX_CSTATE_OPEN)
+ (void) agentx_session_close(axs, AX_CLOSE_SHUTDOWN);
+
+ TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, tsac) {
+ if (axc->axc_dstate != AX_DSTATE_CLOSE)
+ agentx_context_free(axc);
+ }
+
+ if (axs->axs_cstate == AX_CSTATE_CLOSE)
+ agentx_session_free_finalize(axs);
+}
+
+static void
+agentx_session_free_finalize(struct agentx_session *axs)
+{
+ struct agentx *ax = axs->axs_ax;
+
+#ifdef AX_DEBUG
+ if (axs->axs_cstate != AX_CSTATE_CLOSE)
+ agentx_log_axs_fatalx(axs, "%s: free without closing",
+ __func__);
+ if (!TAILQ_EMPTY(&(axs->axs_contexts)))
+ agentx_log_axs_fatalx(axs,
+ "%s: agentx still has contexts", __func__);
+#endif
+
+ TAILQ_REMOVE(&(ax->ax_sessions), axs, axs_ax_sessions);
+ free(axs->axs_descr.aos_string);
+ free(axs);
+
+ if (TAILQ_EMPTY(&(ax->ax_sessions)) && ax->ax_dstate == AX_DSTATE_CLOSE)
+ agentx_free_finalize(ax);
+}
+
+static void
+agentx_session_reset(struct agentx_session *axs)
+{
+ struct agentx_context *axc, *tsac;
+
+ axs->axs_cstate = AX_CSTATE_CLOSE;
+
+ TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, tsac)
+ agentx_context_reset(axc);
+
+ if (axs->axs_dstate == AX_DSTATE_CLOSE)
+ agentx_session_free_finalize(axs);
+}
+
+struct agentx_context *
+agentx_context(struct agentx_session *axs, const char *name)
+{
+ struct agentx_context *axc;
+
+ if (axs->axs_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axs_fatalx(axs, "%s: use after free", __func__);
+
+ if ((axc = calloc(1, sizeof(*axc))) == NULL)
+ return NULL;
+
+ axc->axc_axs = axs;
+ axc->axc_name_default = (name == NULL);
+ if (name != NULL) {
+ axc->axc_name.aos_string = (unsigned char *)strdup(name);
+ if (axc->axc_name.aos_string == NULL) {
+ free(axc);
return NULL;
}
+ axc->axc_name.aos_slen = strlen(name);
}
+ axc->axc_cstate = axs->axs_cstate == AX_CSTATE_OPEN ?
+ AX_CSTATE_OPEN : AX_CSTATE_CLOSE;
+ axc->axc_dstate = AX_DSTATE_OPEN;
+ TAILQ_INIT(&(axc->axc_agentcaps));
+ TAILQ_INIT(&(axc->axc_regions));
+
+ TAILQ_INSERT_HEAD(&(axs->axs_contexts), axc, axc_axs_contexts);
- if ((pdu = calloc(1, sizeof(*pdu))) == NULL)
+ return axc;
+}
+
+static void
+agentx_context_start(struct agentx_context *axc)
+{
+ struct agentx_agentcaps *axa;
+ struct agentx_region *axr;
+
+#ifdef AX_DEBUG
+ if (axc->axc_cstate != AX_CSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected context start",
+ __func__);
+#endif
+ axc->axc_cstate = AX_CSTATE_OPEN;
+
+ TAILQ_FOREACH(axa, &(axc->axc_agentcaps), axa_axc_agentcaps) {
+ if (agentx_agentcaps_start(axa) == -1)
+ return;
+ }
+ TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
+ if (agentx_region_start(axr) == -1)
+ return;
+ }
+}
+
+uint32_t
+agentx_context_uptime(struct agentx_context *axc)
+{
+ struct timespec cur, res;
+
+ if (axc->axc_sysuptimespec.tv_sec == 0 &&
+ axc->axc_sysuptimespec.tv_nsec == 0)
+ return 0;
+
+ (void) clock_gettime(CLOCK_MONOTONIC, &cur);
+
+ timespecsub(&cur, &(axc->axc_sysuptimespec), &res);
+
+ return axc->axc_sysuptime +
+ (uint32_t) ((res.tv_sec * 100) + (res.tv_nsec / 10000000));
+}
+
+struct agentx_object *
+agentx_context_object_find(struct agentx_context *axc,
+ const uint32_t oid[], size_t oidlen, int active, int instance)
+{
+ struct agentx_object *axo, axo_search;
+ size_t i;
+
+ for (i = 0; i < oidlen; i++)
+ axo_search.axo_oid.aoi_id[i] = oid[i];
+ axo_search.axo_oid.aoi_idlen = oidlen;
+
+ axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
+ while (axo == NULL && !instance && axo_search.axo_oid.aoi_idlen > 0) {
+ axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
+ axo_search.axo_oid.aoi_idlen--;
+ }
+ if (active && axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
return NULL;
+ return axo;
+}
- memcpy(&(pdu->ap_header), &header, sizeof(header));
-
-#if defined(AGENTX_DEBUG) && defined(AGENTX_DEBUG_VERBOSE)
- {
- char chars[4];
- int print = 1;
-
- fprintf(stderr, "received packet:\n");
- for (i = 0; i < pdu->ap_header.aph_plength + AGENTX_PDU_HEADER;
- i++) {
- fprintf(stderr, "%02hhx ", ax->ax_rbuf[i]);
- chars[i % 4] = ax->ax_rbuf[i];
- if (!isprint(ax->ax_rbuf[i]))
- print = 0;
- if (i % 4 == 3) {
- if (print)
- fprintf(stderr, "%.4s", chars);
- fprintf(stderr, "\n");
- print = 1;
- }
- }
+struct agentx_object *
+agentx_context_object_nfind(struct agentx_context *axc,
+ const uint32_t oid[], size_t oidlen, int active, int inclusive)
+{
+ struct agentx_object *axo, axo_search;
+ size_t i;
+
+ for (i = 0; i < oidlen; i++)
+ axo_search.axo_oid.aoi_id[i] = oid[i];
+ axo_search.axo_oid.aoi_idlen = oidlen;
+
+ axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
+ if (!inclusive && axo != NULL &&
+ ax_oid_cmp(&(axo_search.axo_oid), &(axo->axo_oid)) <= 0) {
+ axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
}
+
+ while (active && axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
+ axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
+ return axo;
+}
+
+void
+agentx_context_free(struct agentx_context *axc)
+{
+ struct agentx_agentcaps *axa, *tsaa;
+ struct agentx_region *axr, *tsar;
+
+ if (axc == NULL)
+ return;
+
+#ifdef AX_DEBUG
+ if (axc->axc_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: double free", __func__);
#endif
+ axc->axc_dstate = AX_DSTATE_CLOSE;
- u8 = (ax->ax_rbuf) + AGENTX_PDU_HEADER;
- rawlen = pdu->ap_header.aph_plength;
- if (pdu->ap_header.aph_flags & AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT) {
- nread = agentx_pdutoostring(&header, &(pdu->ap_context), u8,
- rawlen);
- if (nread == -1)
- goto fail;
- rawlen -= nread;
- u8 += nread;
+ TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps,
+ tsaa) {
+ if (axa->axa_dstate != AX_DSTATE_CLOSE)
+ agentx_agentcaps_free(axa);
}
+ TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, tsar) {
+ if (axr->axr_dstate != AX_DSTATE_CLOSE)
+ agentx_region_free(axr);
+ }
+}
- switch (pdu->ap_header.aph_type) {
- case AGENTX_PDU_TYPE_GETBULK:
- if (rawlen < 4) {
- errno = EPROTO;
- goto fail;
- }
- pdu->ap_payload.ap_getbulk.ap_nonrep =
- agentx_pdutoh16(&header, u8);
- u8 += 2;
- pdu->ap_payload.ap_getbulk.ap_maxrep =
- agentx_pdutoh16(&header, u8);
- u8 += 2;
- srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
- rawlen -= 4;
- /* FALLTHROUGH */
- case AGENTX_PDU_TYPE_GET:
- case AGENTX_PDU_TYPE_GETNEXT:
- if (pdu->ap_header.aph_type != AGENTX_PDU_TYPE_GETBULK)
- srl = &(pdu->ap_payload.ap_srl);
- while (rawlen > 0 ) {
- srl->ap_nsr++;
- sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr));
- if (sr == NULL)
- goto fail;
- srl->ap_sr = sr;
- sr += (srl->ap_nsr - 1);
- if ((nread = agentx_pdutooid(&header, &(sr->asr_start),
- u8, rawlen)) == -1)
- goto fail;
- rawlen -= nread;
- u8 += nread;
- if ((nread = agentx_pdutooid(&header, &(sr->asr_stop),
- u8, rawlen)) == -1)
- goto fail;
- rawlen -= nread;
- u8 += nread;
- }
- break;
- case AGENTX_PDU_TYPE_TESTSET:
- vbl = &(pdu->ap_payload.ap_vbl);
- while (rawlen > 0) {
- varbind = recallocarray(vbl->ap_varbind,
- vbl->ap_nvarbind, vbl->ap_nvarbind + 1,
- sizeof(*(vbl->ap_varbind)));
- if (varbind == NULL)
- goto fail;
- vbl->ap_varbind = varbind;
- nread = agentx_pdutovarbind(&header,
- &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen);
- if (nread == -1)
- goto fail;
- vbl->ap_nvarbind++;
- u8 += nread;
- rawlen -= nread;
- }
- break;
- case AGENTX_PDU_TYPE_COMMITSET:
- case AGENTX_PDU_TYPE_UNDOSET:
- case AGENTX_PDU_TYPE_CLEANUPSET:
- if (rawlen != 0) {
- errno = EPROTO;
- goto fail;
- }
- break;
- case AGENTX_PDU_TYPE_RESPONSE:
- if (ax->ax_packetids != NULL) {
- found = 0;
- for (i = 0; ax->ax_packetids[i] != 0; i++) {
- if (ax->ax_packetids[i] ==
- pdu->ap_header.aph_packetid) {
- packetidx = i;
- found = 1;
- }
- }
- if (found) {
- ax->ax_packetids[packetidx] =
- ax->ax_packetids[i - 1];
- ax->ax_packetids[i - 1] = 0;
- } else {
- errno = EPROTO;
- goto fail;
- }
- }
- if (rawlen < 8) {
- errno = EPROTO;
- goto fail;
- }
- response = &(pdu->ap_payload.ap_response);
- response->ap_uptime = agentx_pdutoh32(&header, u8);
- u8 += 4;
- response->ap_error = agentx_pdutoh16(&header, u8);
- u8 += 2;
- response->ap_index = agentx_pdutoh16(&header, u8);
- u8 += 2;
- rawlen -= 8;
- while (rawlen > 0) {
- varbind = recallocarray(response->ap_varbindlist,
- response->ap_nvarbind, response->ap_nvarbind + 1,
- sizeof(*(response->ap_varbindlist)));
- if (varbind == NULL)
- goto fail;
- response->ap_varbindlist = varbind;
- nread = agentx_pdutovarbind(&header,
- &(response->ap_varbindlist[response->ap_nvarbind]),
- u8, rawlen);
- if (nread == -1)
- goto fail;
- response->ap_nvarbind++;
- u8 += nread;
- rawlen -= nread;
- }
- break;
- default:
- pdu->ap_payload.ap_raw = malloc(pdu->ap_header.aph_plength);
- if (pdu->ap_payload.ap_raw == NULL)
- goto fail;
- memcpy(pdu->ap_payload.ap_raw, ax->ax_rbuf + AGENTX_PDU_HEADER,
- pdu->ap_header.aph_plength);
- break;
+static void
+agentx_context_free_finalize(struct agentx_context *axc)
+{
+ struct agentx_session *axs = axc->axc_axs;
+
+#ifdef AX_DEBUG
+ if (axc->axc_dstate != AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected context free",
+ __func__);
+#endif
+ if (!TAILQ_EMPTY(&(axc->axc_regions)) ||
+ !TAILQ_EMPTY(&(axc->axc_agentcaps)))
+ return;
+ TAILQ_REMOVE(&(axs->axs_contexts), axc, axc_axs_contexts);
+ free(axc->axc_name.aos_string);
+ free(axc);
+}
+
+static void
+agentx_context_reset(struct agentx_context *axc)
+{
+ struct agentx_agentcaps *axa, *tsaa;
+ struct agentx_region *axr, *tsar;
+
+ axc->axc_cstate = AX_CSTATE_CLOSE;
+ axc->axc_sysuptimespec.tv_sec = 0;
+ axc->axc_sysuptimespec.tv_nsec = 0;
+
+ TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, tsaa)
+ agentx_agentcaps_reset(axa);
+ TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, tsar)
+ agentx_region_reset(axr);
+
+ if (axc->axc_dstate == AX_DSTATE_CLOSE)
+ agentx_context_free_finalize(axc);
+}
+
+struct agentx_agentcaps *
+agentx_agentcaps(struct agentx_context *axc, uint32_t oid[],
+ size_t oidlen, const char *descr)
+{
+ struct agentx_agentcaps *axa;
+ size_t i;
+
+ if (axc->axc_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: use after free", __func__);
+
+ if ((axa = calloc(1, sizeof(*axa))) == NULL)
+ return NULL;
+
+ axa->axa_axc = axc;
+ for (i = 0; i < oidlen; i++)
+ axa->axa_oid.aoi_id[i] = oid[i];
+ axa->axa_oid.aoi_idlen = oidlen;
+ axa->axa_descr.aos_string = (unsigned char *)strdup(descr);
+ if (axa->axa_descr.aos_string == NULL) {
+ free(axa);
+ return NULL;
}
+ axa->axa_descr.aos_slen = strlen(descr);
+ axa->axa_cstate = AX_CSTATE_CLOSE;
+ axa->axa_dstate = AX_DSTATE_OPEN;
- ax->ax_rblen = 0;
+ TAILQ_INSERT_TAIL(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
- return pdu;
-fail:
- agentx_pdu_free(pdu);
- return NULL;
+ if (axc->axc_cstate == AX_CSTATE_OPEN)
+ agentx_agentcaps_start(axa);
+
+ return axa;
}
static int
-agentx_pdu_need(struct agentx *ax, size_t need)
+agentx_agentcaps_start(struct agentx_agentcaps *axa)
{
- uint8_t *wbuf;
- size_t wbsize;
+ struct agentx_context *axc = axa->axa_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (axc->axc_cstate != AX_CSTATE_OPEN ||
+ axa->axa_cstate != AX_CSTATE_CLOSE ||
+ axa->axa_dstate != AX_DSTATE_OPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: unexpected region registration", __func__);
+#endif
- if (ax->ax_wbtlen >= ax->ax_wbsize) {
- wbsize = ((ax->ax_wbtlen / 512) + 1) * 512;
- wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1);
- if (wbuf == NULL) {
- ax->ax_wbtlen = ax->ax_wblen;
- return -1;
- }
- ax->ax_wbsize = wbsize;
- ax->ax_wbuf = wbuf;
+ packetid = ax_addagentcaps(ax->ax_ax, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), &(axa->axa_oid), &(axa->axa_descr));
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_ADDAGENTCAPS));
+ agentx_reset(ax);
+ return -1;
+ }
+ agentx_log_axc_info(axc, "agentcaps %s: opening",
+ ax_oid2string(&(axa->axa_oid)));
+ axa->axa_cstate = AX_CSTATE_WAITOPEN;
+ return agentx_request(ax, packetid, agentx_agentcaps_finalize,
+ axa);
+}
+
+static int
+agentx_agentcaps_finalize(struct ax_pdu *pdu, void *cookie)
+{
+ struct agentx_agentcaps *axa = cookie;
+ struct agentx_context *axc = axa->axa_axc;
+
+#ifdef AX_DEBUG
+ if (axa->axa_cstate != AX_CSTATE_WAITOPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: not expecting agentcaps open", __func__);
+#endif
+
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ /* Agentcaps failing is nothing too serious */
+ agentx_log_axc_warn(axc, "agentcaps %s: %s",
+ ax_oid2string(&(axa->axa_oid)),
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ axa->axa_cstate = AX_CSTATE_CLOSE;
+ return 0;
}
+ axa->axa_cstate = AX_CSTATE_OPEN;
+
+ agentx_log_axc_info(axc, "agentcaps %s: open",
+ ax_oid2string(&(axa->axa_oid)));
+
+ if (axa->axa_dstate == AX_DSTATE_CLOSE)
+ agentx_agentcaps_close(axa);
+
return 0;
}
-ssize_t
-agentx_send(struct agentx *ax)
+static int
+agentx_agentcaps_close(struct agentx_agentcaps *axa)
+{
+ struct agentx_context *axc = axa->axa_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (axa->axa_cstate != AX_CSTATE_OPEN)
+ agentx_log_axc_fatalx(axc, "%s: unexpected agentcaps close",
+ __func__);
+#endif
+
+ axa->axa_cstate = AX_CSTATE_WAITCLOSE;
+ if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
+ return 0;
+
+ packetid = ax_removeagentcaps(ax->ax_ax, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), &(axa->axa_oid));
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_REMOVEAGENTCAPS));
+ agentx_reset(ax);
+ return -1;
+ }
+ agentx_log_axc_info(axc, "agentcaps %s: closing",
+ ax_oid2string(&(axa->axa_oid)));
+ return agentx_request(ax, packetid,
+ agentx_agentcaps_close_finalize, axa);
+}
+
+static int
+agentx_agentcaps_close_finalize(struct ax_pdu *pdu, void *cookie)
{
- ssize_t nwrite;
+ struct agentx_agentcaps *axa = cookie;
+ struct agentx_context *axc = axa->axa_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+
+#ifdef AX_DEBUG
+ if (axa->axa_cstate != AX_CSTATE_WAITCLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected agentcaps close",
+ __func__);
+#endif
- if (ax->ax_wblen != ax->ax_wbtlen) {
- errno = EALREADY;
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ agentx_log_axc_warnx(axc, "agentcaps %s: %s",
+ ax_oid2string(&(axa->axa_oid)),
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ agentx_reset(ax);
return -1;
}
- if (ax->ax_wblen == 0)
+ axa->axa_cstate = AX_CSTATE_CLOSE;
+
+ agentx_log_axc_info(axc, "agentcaps %s: closed",
+ ax_oid2string(&(axa->axa_oid)));
+
+ if (axa->axa_dstate == AX_DSTATE_CLOSE) {
+ agentx_agentcaps_free_finalize(axa);
return 0;
+ } else {
+ if (axc->axc_cstate == AX_CSTATE_OPEN) {
+ if (agentx_agentcaps_start(axa) == -1)
+ return -1;
+ }
+ }
+ return 0;
+}
-#if defined(AGENTX_DEBUG) && defined(AGENTX_DEBUG_VERBOSE)
- {
- size_t i;
- char chars[4];
- int print = 1;
-
- fprintf(stderr, "sending packet:\n");
- for (i = 0; i < ax->ax_wblen; i++) {
- fprintf(stderr, "%02hhx ", ax->ax_wbuf[i]);
- chars[i % 4] = ax->ax_wbuf[i];
- if (!isprint(ax->ax_wbuf[i]))
- print = 0;
- if (i % 4 == 3) {
- if (print)
- fprintf(stderr, "%.4s", chars);
- fprintf(stderr, "\n");
- print = 1;
- }
+void
+agentx_agentcaps_free(struct agentx_agentcaps *axa)
+{
+ if (axa == NULL)
+ return;
+
+ if (axa->axa_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axa->axa_axc, "%s: double free",
+ __func__);
+
+ axa->axa_dstate = AX_DSTATE_CLOSE;
+
+ if (axa->axa_cstate == AX_CSTATE_OPEN) {
+ if (agentx_agentcaps_close(axa) == -1)
+ return;
+ }
+
+ if (axa->axa_cstate == AX_CSTATE_CLOSE)
+ agentx_agentcaps_free_finalize(axa);
+}
+
+static void
+agentx_agentcaps_free_finalize(struct agentx_agentcaps *axa)
+{
+ struct agentx_context *axc = axa->axa_axc;
+
+#ifdef AX_DEBUG
+ if (axa->axa_dstate != AX_DSTATE_CLOSE ||
+ axa->axa_cstate != AX_CSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected free", __func__);
+#endif
+
+ TAILQ_REMOVE(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
+ free(axa->axa_descr.aos_string);
+ free(axa);
+
+ if (axc->axc_dstate == AX_DSTATE_CLOSE)
+ agentx_context_free_finalize(axc);
+}
+
+static void
+agentx_agentcaps_reset(struct agentx_agentcaps *axa)
+{
+ axa->axa_cstate = AX_CSTATE_CLOSE;
+
+ if (axa->axa_dstate == AX_DSTATE_CLOSE)
+ agentx_agentcaps_free_finalize(axa);
+}
+
+struct agentx_region *
+agentx_region(struct agentx_context *axc, uint32_t oid[],
+ size_t oidlen, uint8_t timeout)
+{
+ struct agentx_region *axr;
+ struct ax_oid tmpoid;
+ size_t i;
+
+ if (axc->axc_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: use after free", __func__);
+ if (oidlen < 1) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axc, "%s: oidlen == 0", __func__);
+#else
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axc, "%s: oidlen > %d", __func__,
+ AGENTX_OID_MAX_LEN);
+#else
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ for (i = 0; i < oidlen; i++)
+ tmpoid.aoi_id[i] = oid[i];
+ tmpoid.aoi_idlen = oidlen;
+ TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
+ if (ax_oid_cmp(&(axr->axr_oid), &tmpoid) == 0) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axc,
+ "%s: duplicate region registration", __func__);
+#else
+ errno = EINVAL;
+ return NULL;
+#endif
}
}
+
+ if ((axr = calloc(1, sizeof(*axr))) == NULL)
+ return NULL;
+
+ axr->axr_axc = axc;
+ axr->axr_timeout = timeout;
+ axr->axr_priority = AX_PRIORITY_DEFAULT;
+ bcopy(&tmpoid, &(axr->axr_oid), sizeof(axr->axr_oid));
+ axr->axr_cstate = AX_CSTATE_CLOSE;
+ axr->axr_dstate = AX_DSTATE_OPEN;
+ TAILQ_INIT(&(axr->axr_indices));
+ TAILQ_INIT(&(axr->axr_objects));
+
+ TAILQ_INSERT_HEAD(&(axc->axc_regions), axr, axr_axc_regions);
+
+ if (axc->axc_cstate == AX_CSTATE_OPEN)
+ (void) agentx_region_start(axr);
+
+ return axr;
+}
+
+static int
+agentx_region_start(struct agentx_region *axr)
+{
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (axc->axc_cstate != AX_CSTATE_OPEN ||
+ axr->axr_cstate != AX_CSTATE_CLOSE ||
+ axr->axr_dstate != AX_DSTATE_OPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: unexpected region registration", __func__);
#endif
- if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen,
- MSG_NOSIGNAL | MSG_DONTWAIT)) == -1)
+ packetid = ax_register(ax->ax_ax, 0, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), axr->axr_timeout, axr->axr_priority,
+ 0, &(axr->axr_oid), 0);
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_REGISTER));
+ agentx_reset(ax);
return -1;
+ }
+ agentx_log_axc_info(axc, "region %s: opening",
+ ax_oid2string(&(axr->axr_oid)));
+ axr->axr_cstate = AX_CSTATE_WAITOPEN;
+ return agentx_request(ax, packetid, agentx_region_finalize, axr);
+}
+
+static int
+agentx_region_finalize(struct ax_pdu *pdu, void *cookie)
+{
+ struct agentx_region *axr = cookie;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct agentx_index *axi;
+ struct agentx_object *axo;
+
+#ifdef AX_DEBUG
+ if (axr->axr_cstate != AX_CSTATE_WAITOPEN)
+ agentx_log_axc_fatalx(axc, "%s: not expecting region open",
+ __func__);
+#endif
- memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite);
- ax->ax_wblen -= nwrite;
- ax->ax_wbtlen = ax->ax_wblen;
+ if (pdu->ap_payload.ap_response.ap_error == AX_PDU_ERROR_NOERROR) {
+ axr->axr_cstate = AX_CSTATE_OPEN;
+ agentx_log_axc_info(axc, "region %s: open",
+ ax_oid2string(&(axr->axr_oid)));
+ } else if (pdu->ap_payload.ap_response.ap_error ==
+ AX_PDU_ERROR_DUPLICATEREGISTRATION) {
+ axr->axr_cstate = AX_CSTATE_CLOSE;
+ /* Try at lower priority: first come first serve */
+ if ((++axr->axr_priority) != 0) {
+ agentx_log_axc_warnx(axc, "region %s: duplicate, "
+ "reducing priority",
+ ax_oid2string(&(axr->axr_oid)));
+ return agentx_region_start(axr);
+ }
+ agentx_log_axc_info(axc, "region %s: duplicate, can't "
+ "reduce priority, ignoring",
+ ax_oid2string(&(axr->axr_oid)));
+ } else if (pdu->ap_payload.ap_response.ap_error ==
+ AX_PDU_ERROR_REQUESTDENIED) {
+ axr->axr_cstate = AX_CSTATE_CLOSE;
+ agentx_log_axc_warnx(axc, "region %s: %s",
+ ax_oid2string(&(axr->axr_oid)),
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ /*
+ * If we can't register a region, related objects are useless.
+ * But no need to retry.
+ */
+ return 0;
+ } else {
+ agentx_log_axc_info(axc, "region %s: %s",
+ ax_oid2string(&(axr->axr_oid)),
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ agentx_reset(ax);
+ return -1;
+ }
- return ax->ax_wblen;
+ if (axr->axr_dstate == AX_DSTATE_CLOSE) {
+ if (agentx_region_close(axr) == -1)
+ return -1;
+ } else {
+ TAILQ_FOREACH(axi, &(axr->axr_indices), axi_axr_indices) {
+ if (agentx_index_start(axi) == -1)
+ return -1;
+ }
+ TAILQ_FOREACH(axo, &(axr->axr_objects), axo_axr_objects) {
+ if (agentx_object_start(axo) == -1)
+ return -1;
+ }
+ }
+ return 0;
}
-uint32_t
-agentx_open(struct agentx *ax, uint8_t timeout, struct agentx_oid *oid,
- struct agentx_ostring *descr)
+static int
+agentx_region_close(struct agentx_region *axr)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_OPEN, 0, 0, 0, 0,
- NULL) == -1)
- return 0;
- agentx_pdu_need(ax, 4);
- ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
- memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
- ax->ax_wbtlen += 3;
- if (agentx_pdu_add_oid(ax, oid, 0) == -1)
- return 0;
- if (agentx_pdu_add_str(ax, descr) == -1)
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (axr->axr_cstate != AX_CSTATE_OPEN)
+ agentx_log_axc_fatalx(axc, "%s: unexpected region close",
+ __func__);
+#endif
+
+ axr->axr_cstate = AX_CSTATE_WAITCLOSE;
+ if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
return 0;
- return agentx_pdu_queue(ax);
+ packetid = ax_unregister(ax->ax_ax, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), axr->axr_priority, 0, &(axr->axr_oid),
+ 0);
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
+ agentx_reset(ax);
+ return -1;
+ }
+ agentx_log_axc_info(axc, "region %s: closing",
+ ax_oid2string(&(axr->axr_oid)));
+ return agentx_request(ax, packetid, agentx_region_close_finalize,
+ axr);
}
-uint32_t
-agentx_close(struct agentx *ax, uint32_t sessionid,
- enum agentx_close_reason reason)
+static int
+agentx_region_close_finalize(struct ax_pdu *pdu, void *cookie)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_CLOSE, 0, sessionid, 0, 0,
- NULL) == -1)
- return 0;
+ struct agentx_region *axr = cookie;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+
+#ifdef AX_DEBUG
+ if (axr->axr_cstate != AX_CSTATE_WAITCLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected region close",
+ __func__);
+#endif
+
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ agentx_log_axc_warnx(axc, "closing %s: %s",
+ ax_oid2string(&(axr->axr_oid)),
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ agentx_reset(ax);
+ return -1;
+ }
- if (agentx_pdu_need(ax, 4) == -1)
+ axr->axr_priority = AX_PRIORITY_DEFAULT;
+ axr->axr_cstate = AX_CSTATE_CLOSE;
+
+ agentx_log_axc_info(axc, "region %s: closed",
+ ax_oid2string(&(axr->axr_oid)));
+
+ if (axr->axr_dstate == AX_DSTATE_CLOSE) {
+ agentx_region_free_finalize(axr);
return 0;
- ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason;
- memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
- ax->ax_wbtlen += 3;
+ } else {
+ if (axc->axc_cstate == AX_CSTATE_OPEN) {
+ if (agentx_region_start(axr) == -1)
+ return -1;
+ }
+ }
+ return 0;
+}
- return agentx_pdu_queue(ax);
+void
+agentx_region_free(struct agentx_region *axr)
+{
+ struct agentx_index *axi, *tsai;
+ struct agentx_object *axo, *tsao;
+
+ if (axr == NULL)
+ return;
+
+ if (axr->axr_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: double free",
+ __func__);
+
+ axr->axr_dstate = AX_DSTATE_CLOSE;
+
+ TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, tsai) {
+ if (axi->axi_dstate != AX_DSTATE_CLOSE)
+ agentx_index_free(axi);
+ }
+
+ TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, tsao) {
+ if (axo->axo_dstate != AX_DSTATE_CLOSE)
+ agentx_object_free(axo);
+ }
+
+ if (axr->axr_cstate == AX_CSTATE_OPEN) {
+ if (agentx_region_close(axr) == -1)
+ return;
+ }
+
+ if (axr->axr_cstate == AX_CSTATE_CLOSE)
+ agentx_region_free_finalize(axr);
}
-uint32_t
-agentx_indexallocate(struct agentx *ax, uint8_t flags, uint32_t sessionid,
- struct agentx_ostring *context, struct agentx_varbind *vblist, size_t nvb)
+static void
+agentx_region_free_finalize(struct agentx_region *axr)
{
- if (flags & ~(AGENTX_PDU_FLAG_NEW_INDEX | AGENTX_PDU_FLAG_ANY_INDEX)) {
+ struct agentx_context *axc = axr->axr_axc;
+
+#ifdef AX_DEBUG
+ if (axr->axr_dstate != AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected free", __func__);
+#endif
+
+ if (!TAILQ_EMPTY(&(axr->axr_indices)) ||
+ !TAILQ_EMPTY(&(axr->axr_objects)))
+ return;
+
+ if (axr->axr_cstate != AX_CSTATE_CLOSE)
+ return;
+
+ TAILQ_REMOVE(&(axc->axc_regions), axr, axr_axc_regions);
+ free(axr);
+
+ if (axc->axc_dstate == AX_DSTATE_CLOSE)
+ agentx_context_free_finalize(axc);
+}
+
+static void
+agentx_region_reset(struct agentx_region *axr)
+{
+ struct agentx_index *axi, *tsai;
+ struct agentx_object *axo, *tsao;
+
+ axr->axr_cstate = AX_CSTATE_CLOSE;
+ axr->axr_priority = AX_PRIORITY_DEFAULT;
+
+ TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, tsai)
+ agentx_index_reset(axi);
+ TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, tsao)
+ agentx_object_reset(axo);
+
+ if (axr->axr_dstate == AX_DSTATE_CLOSE)
+ agentx_region_free_finalize(axr);
+}
+
+struct agentx_index *
+agentx_index_integer_new(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen)
+{
+ struct ax_varbind vb;
+ size_t i;
+
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
errno = EINVAL;
- return 0;
+ return NULL;
+#endif
}
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_INDEXALLOCATE, flags,
- sessionid, 0, 0, context) == -1)
- return 0;
+ vb.avb_type = AX_DATA_TYPE_INTEGER;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_uint32 = 0;
- if (agentx_pdu_add_varbindlist(ax, vblist, nvb) == -1)
- return 0;
+ return agentx_index(axr, &vb, AXI_TYPE_NEW);
+}
- return agentx_pdu_queue(ax);
+struct agentx_index *
+agentx_index_integer_any(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen)
+{
+ struct ax_varbind vb;
+ size_t i;
+
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ vb.avb_type = AX_DATA_TYPE_INTEGER;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_uint32 = 0;
+
+ return agentx_index(axr, &vb, AXI_TYPE_ANY);
}
-uint32_t
-agentx_indexdeallocate(struct agentx *ax, uint32_t sessionid,
- struct agentx_ostring *context, struct agentx_varbind *vblist, size_t nvb)
+struct agentx_index *
+agentx_index_integer_value(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen, uint32_t value)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_INDEXDEALLOCATE, 0,
- sessionid, 0, 0, context) == -1)
- return 0;
+ struct ax_varbind vb;
+ size_t i;
- if (agentx_pdu_add_varbindlist(ax, vblist, nvb) == -1)
- return 0;
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ vb.avb_type = AX_DATA_TYPE_INTEGER;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_uint32 = value;
- return agentx_pdu_queue(ax);
+ return agentx_index(axr, &vb, AXI_TYPE_VALUE);
}
-uint32_t
-agentx_addagentcaps(struct agentx *ax, uint32_t sessionid,
- struct agentx_ostring *context, struct agentx_oid *id,
- struct agentx_ostring *descr)
+struct agentx_index *
+agentx_index_integer_dynamic(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_ADDAGENTCAPS, 0,
- sessionid, 0, 0, context) == -1)
- return 0;
- if (agentx_pdu_add_oid(ax, id, 0) == -1)
- return 0;
- if (agentx_pdu_add_str(ax, descr) == -1)
- return 0;
+ struct ax_varbind vb;
+ size_t i;
+
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ vb.avb_type = AX_DATA_TYPE_INTEGER;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
- return agentx_pdu_queue(ax);
+ return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
}
-uint32_t
-agentx_removeagentcaps(struct agentx *ax, uint32_t sessionid,
- struct agentx_ostring *context, struct agentx_oid *id)
+struct agentx_index *
+agentx_index_string_dynamic(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_REMOVEAGENTCAPS, 0,
- sessionid, 0, 0, context) == -1)
- return 0;
- if (agentx_pdu_add_oid(ax, id, 0) == -1)
- return 0;
+ struct ax_varbind vb;
+ size_t i;
- return agentx_pdu_queue(ax);
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_ostring.aos_slen = 0;
+ vb.avb_data.avb_ostring.aos_string = NULL;
+ return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
}
-uint32_t
-agentx_register(struct agentx *ax, uint8_t flags, uint32_t sessionid,
- struct agentx_ostring *context, uint8_t timeout, uint8_t priority,
- uint8_t range_subid, struct agentx_oid *subtree, uint32_t upperbound)
+struct agentx_index *
+agentx_index_nstring_dynamic(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen, size_t vlen)
{
- if (flags & ~(AGENTX_PDU_FLAG_INSTANCE_REGISTRATION)) {
+ struct ax_varbind vb;
+ size_t i;
+
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
errno = EINVAL;
- return 0;
+ return NULL;
+#endif
+ }
+ if (vlen == 0 || vlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid string "
+ "length: %zu\n", __func__, vlen);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: invalid string "
+ "length: %zu\n", __func__, vlen);
+ errno = EINVAL;
+ return NULL;
+#endif
}
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_REGISTER, flags,
- sessionid, 0, 0, context) == -1)
- return 0;
+ vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_ostring.aos_slen = vlen;
+ vb.avb_data.avb_ostring.aos_string = NULL;
- if (agentx_pdu_need(ax, 4) == -1)
- return 0;
- ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
- ax->ax_wbuf[ax->ax_wbtlen++] = priority;
- ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
- ax->ax_wbuf[ax->ax_wbtlen++] = 0;
- if (agentx_pdu_add_oid(ax, subtree, 0) == -1)
- return 0;
- if (range_subid != 0) {
- if (agentx_pdu_add_uint32(ax, upperbound) == -1)
- return 0;
+ return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
+}
+
+struct agentx_index *
+agentx_index_oid_dynamic(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen)
+{
+ struct ax_varbind vb;
+ size_t i;
+
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
}
- return agentx_pdu_queue(ax);
+ vb.avb_type = AX_DATA_TYPE_OID;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_oid.aoi_idlen = 0;
+
+ return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
}
-uint32_t
-agentx_unregister(struct agentx *ax, uint32_t sessionid,
- struct agentx_ostring *context, uint8_t priority, uint8_t range_subid,
- struct agentx_oid *subtree, uint32_t upperbound)
+struct agentx_index *
+agentx_index_noid_dynamic(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen, size_t vlen)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_UNREGISTER, 0,
- sessionid, 0, 0, context) == -1)
- return 0;
+ struct ax_varbind vb;
+ size_t i;
- if (agentx_pdu_need(ax, 4) == -1)
- return 0;
- ax->ax_wbuf[ax->ax_wbtlen++] = 0;
- ax->ax_wbuf[ax->ax_wbtlen++] = priority;
- ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
- ax->ax_wbuf[ax->ax_wbtlen++] = 0;
- if (agentx_pdu_add_oid(ax, subtree, 0) == -1)
- return 0;
- if (range_subid != 0) {
- if (agentx_pdu_add_uint32(ax, upperbound) == -1)
- return 0;
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
}
+ if (vlen == 0 || vlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid string "
+ "length: %zu\n", __func__, vlen);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: invalid string "
+ "length: %zu\n", __func__, vlen);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ vb.avb_type = AX_DATA_TYPE_OID;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_oid.aoi_idlen = oidlen;
+ vb.avb_data.avb_oid.aoi_idlen = vlen;
- return agentx_pdu_queue(ax);
+ return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
}
-int
-agentx_response(struct agentx *ax, uint32_t sessionid, uint32_t transactionid,
- uint32_t packetid, struct agentx_ostring *context, uint32_t sysuptime,
- uint16_t error, uint16_t index, struct agentx_varbind *vblist, size_t nvb)
+struct agentx_index *
+agentx_index_ipaddress_dynamic(struct agentx_region *axr, uint32_t oid[],
+ size_t oidlen)
{
- if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_RESPONSE, 0, sessionid,
- transactionid, packetid, context) == -1)
- return -1;
+ struct ax_varbind vb;
+ size_t i;
+
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+
+ vb.avb_type = AX_DATA_TYPE_IPADDRESS;
+ for (i = 0; i < oidlen; i++)
+ vb.avb_oid.aoi_id[i] = oid[i];
+ vb.avb_data.avb_ostring.aos_string = NULL;
+ vb.avb_oid.aoi_idlen = oidlen;
+
+ return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
+}
+
+static struct agentx_index *
+agentx_index(struct agentx_region *axr, struct ax_varbind *vb,
+ enum agentx_index_type type)
+{
+ struct agentx_index *axi;
+
+ if (axr->axr_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
+ __func__);
+ if (ax_oid_cmp(&(axr->axr_oid), &(vb->avb_oid)) != -2) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oid is not child "
+ "of region %s", __func__,
+ ax_oid2string(&(vb->avb_oid)));
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oid is not child of "
+ "region %s", __func__, ax_oid2string(&(vb->avb_oid)));
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
- if (agentx_pdu_add_uint32(ax, sysuptime) == -1 ||
- agentx_pdu_add_uint16(ax, error) == -1 ||
- agentx_pdu_add_uint16(ax, index) == -1)
+ if ((axi = calloc(1, sizeof(*axi))) == NULL)
+ return NULL;
+
+ axi->axi_axr = axr;
+ axi->axi_type = type;
+ bcopy(vb, &(axi->axi_vb), sizeof(*vb));
+ axi->axi_cstate = AX_CSTATE_CLOSE;
+ axi->axi_dstate = AX_DSTATE_OPEN;
+ TAILQ_INSERT_HEAD(&(axr->axr_indices), axi, axi_axr_indices);
+
+ if (axr->axr_cstate == AX_CSTATE_OPEN)
+ agentx_index_start(axi);
+
+ return axi;
+}
+
+static int
+agentx_index_start(struct agentx_index *axi)
+{
+ struct agentx_region *axr = axi->axi_axr;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+ int flags = 0;
+
+#ifdef AX_DEBUG
+ if (axr->axr_cstate != AX_CSTATE_OPEN ||
+ axi->axi_cstate != AX_CSTATE_CLOSE ||
+ axi->axi_dstate != AX_DSTATE_OPEN)
+ agentx_log_axc_fatalx(axc, "%s: unexpected index allocation",
+ __func__);
+#endif
+
+ axi->axi_cstate = AX_CSTATE_WAITOPEN;
+
+ if (axi->axi_type == AXI_TYPE_NEW)
+ flags = AX_PDU_FLAG_NEW_INDEX;
+ else if (axi->axi_type == AXI_TYPE_ANY)
+ flags = AX_PDU_FLAG_ANY_INDEX;
+ else if (axi->axi_type == AXI_TYPE_DYNAMIC) {
+ agentx_index_finalize(NULL, axi);
+ return 0;
+ }
+
+ /* We might be able to bundle, but if we fail we'd have to reorganise */
+ packetid = ax_indexallocate(ax->ax_ax, flags, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
+ agentx_reset(ax);
return -1;
+ }
+ if (axi->axi_type == AXI_TYPE_VALUE)
+ agentx_log_axc_info(axc, "index %s: allocating '%u'",
+ ax_oid2string(&(axi->axi_vb.avb_oid)),
+ axi->axi_vb.avb_data.avb_uint32);
+ else if (axi->axi_type == AXI_TYPE_ANY)
+ agentx_log_axc_info(axc, "index %s: allocating any index",
+ ax_oid2string(&(axi->axi_vb.avb_oid)));
+ else if (axi->axi_type == AXI_TYPE_NEW)
+ agentx_log_axc_info(axc, "index %s: allocating new index",
+ ax_oid2string(&(axi->axi_vb.avb_oid)));
+
+ return agentx_request(ax, packetid, agentx_index_finalize, axi);
+}
+
+static int
+agentx_index_finalize(struct ax_pdu *pdu, void *cookie)
+{
+ struct agentx_index *axi = cookie;
+ struct agentx_region *axr = axi->axi_axr;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct ax_pdu_response *resp;
+ size_t i;
+
+#ifdef AX_DEBUG
+ if (axi->axi_cstate != AX_CSTATE_WAITOPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: not expecting index allocate", __func__);
+#endif
+ if (axi->axi_type == AXI_TYPE_DYNAMIC) {
+ axi->axi_cstate = AX_CSTATE_OPEN;
+ return 0;
+ }
- if (agentx_pdu_add_varbindlist(ax, vblist, nvb) == -1)
+ resp = &(pdu->ap_payload.ap_response);
+ if (resp->ap_error != AX_PDU_ERROR_NOERROR) {
+ axi->axi_cstate = AX_CSTATE_CLOSE;
+ agentx_log_axc_warnx(axc, "index %s: %s",
+ ax_oid2string(&(axr->axr_oid)),
+ ax_error2string(resp->ap_error));
+ return 0;
+ }
+ axi->axi_cstate = AX_CSTATE_OPEN;
+ if (resp->ap_nvarbind != 1) {
+ agentx_log_axc_warnx(axc, "index %s: unexpected number of "
+ "indices", ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
return -1;
- if (agentx_pdu_queue(ax) == 0)
+ }
+ if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
+ agentx_log_axc_warnx(axc, "index %s: unexpected index type",
+ ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
return -1;
+ }
+ if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
+ &(axi->axi_vb.avb_oid)) != 0) {
+ agentx_log_axc_warnx(axc, "index %s: unexpected oid",
+ ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
+ return -1;
+ }
+
+ switch (axi->axi_vb.avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+ if (axi->axi_type == AXI_TYPE_NEW ||
+ axi->axi_type == AXI_TYPE_ANY)
+ axi->axi_vb.avb_data.avb_uint32 =
+ resp->ap_varbindlist[0].avb_data.avb_uint32;
+ else if (axi->axi_vb.avb_data.avb_uint32 !=
+ resp->ap_varbindlist[0].avb_data.avb_uint32) {
+ agentx_log_axc_warnx(axc, "index %s: unexpected "
+ "index value", ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
+ return -1;
+ }
+ agentx_log_axc_info(axc, "index %s: allocated '%u'",
+ ax_oid2string(&(axi->axi_vb.avb_oid)),
+ axi->axi_vb.avb_data.avb_uint32);
+ break;
+ default:
+ agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
+ __func__);
+ }
+
+ if (axi->axi_dstate == AX_DSTATE_CLOSE)
+ return agentx_index_close(axi);
+
+ /* TODO Make use of range_subid register */
+ for (i = 0; i < axi->axi_objectlen; i++) {
+ if (axi->axi_object[i]->axo_dstate == AX_DSTATE_OPEN) {
+ if (agentx_object_start(axi->axi_object[i]) == -1)
+ return -1;
+ }
+ }
return 0;
}
void
-agentx_pdu_free(struct agentx_pdu *pdu)
+agentx_index_free(struct agentx_index *axi)
{
size_t i;
- struct agentx_pdu_response *response;
+ struct agentx_object *axo;
- if (pdu->ap_header.aph_flags & AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT)
- free(pdu->ap_context.aos_string);
+ if (axi == NULL)
+ return;
- switch (pdu->ap_header.aph_type) {
- case AGENTX_PDU_TYPE_GET:
- case AGENTX_PDU_TYPE_GETNEXT:
- case AGENTX_PDU_TYPE_GETBULK:
- free(pdu->ap_payload.ap_srl.ap_sr);
- break;
- case AGENTX_PDU_TYPE_RESPONSE:
- response = &(pdu->ap_payload.ap_response);
- for (i = 0; i < response->ap_nvarbind; i++)
- agentx_varbind_free(&(response->ap_varbindlist[i]));
- free(response->ap_varbindlist);
- break;
- default:
- free(pdu->ap_payload.ap_raw);
- break;
+ if (axi->axi_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axi->axi_axr->axr_axc,
+ "%s: double free", __func__);
+
+ /* TODO Do a range_subid unregister before freeing */
+ for (i = 0; i < axi->axi_objectlen; i++) {
+ axo = axi->axi_object[i];
+ if (axo->axo_dstate != AX_DSTATE_CLOSE) {
+ agentx_object_free(axo);
+ if (axi->axi_object[i] != axo)
+ i--;
+ }
}
- free(pdu);
+
+ axi->axi_dstate = AX_DSTATE_CLOSE;
+
+ if (axi->axi_cstate == AX_CSTATE_OPEN)
+ (void) agentx_index_close(axi);
+ else if (axi->axi_cstate == AX_CSTATE_CLOSE)
+ agentx_index_free_finalize(axi);
}
-void
-agentx_varbind_free(struct agentx_varbind *varbind)
+static void
+agentx_index_free_finalize(struct agentx_index *axi)
{
- switch (varbind->avb_type) {
- case AGENTX_DATA_TYPE_OCTETSTRING:
- case AGENTX_DATA_TYPE_IPADDRESS:
- case AGENTX_DATA_TYPE_OPAQUE:
- free(varbind->avb_data.avb_ostring.aos_string);
- break;
- default:
- break;
+ struct agentx_region *axr = axi->axi_axr;
+
+#ifdef AX_DEBUG
+ if (axi->axi_dstate != AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: unexpected free",
+ __func__);
+ if (axi->axi_cstate != AX_CSTATE_CLOSE)
+ agentx_log_axc_fatalx(axr->axr_axc,
+ "%s: free without deallocating", __func__);
+#endif
+
+ if (axi->axi_objectlen != 0)
+ return;
+
+ TAILQ_REMOVE(&(axr->axr_indices), axi, axi_axr_indices);
+ ax_varbind_free(&(axi->axi_vb));
+ free(axi->axi_object);
+ free(axi);
+ if (axr->axr_dstate == AX_DSTATE_CLOSE)
+ agentx_region_free_finalize(axr);
+}
+
+static void
+agentx_index_reset(struct agentx_index *axi)
+{
+ axi->axi_cstate = AX_CSTATE_CLOSE;
+
+ if (axi->axi_dstate == AX_DSTATE_CLOSE)
+ agentx_index_free_finalize(axi);
+}
+
+static int
+agentx_index_close(struct agentx_index *axi)
+{
+ struct agentx_region *axr = axi->axi_axr;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ uint32_t packetid;
+
+#ifdef AX_DEBUG
+ if (axi->axi_cstate != AX_CSTATE_OPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: unexpected index deallocation", __func__);
+#endif
+
+ axi->axi_cstate = AX_CSTATE_WAITCLOSE;
+ if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
+ return 0;
+
+ /* We might be able to bundle, but if we fail we'd have to reorganise */
+ packetid = ax_indexdeallocate(ax->ax_ax, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
+ agentx_reset(ax);
+ return -1;
}
+ agentx_log_axc_info(axc, "index %s: deallocating",
+ ax_oid2string(&(axi->axi_vb.avb_oid)));
+ return agentx_request(ax, packetid, agentx_index_close_finalize,
+ axi);
}
-const char *
-agentx_error2string(enum agentx_pdu_error error)
-{
- static char buffer[64];
- switch (error) {
- case AGENTX_PDU_ERROR_NOERROR:
- return "No error";
- case AGENTX_PDU_ERROR_GENERR:
- return "Generic error";
- case AGENTX_PDU_ERROR_NOACCESS:
- return "No access";
- case AGENTX_PDU_ERROR_WRONGTYPE:
- return "Wrong type";
- case AGENTX_PDU_ERROR_WRONGLENGTH:
- return "Wrong length";
- case AGENTX_PDU_ERROR_WRONGENCODING:
- return "Wrong encoding";
- case AGENTX_PDU_ERROR_WRONGVALUE:
- return "Wrong value";
- case AGENTX_PDU_ERROR_NOCREATION:
- return "No creation";
- case AGENTX_PDU_ERROR_INCONSISTENTVALUE:
- return "Inconsistent value";
- case AGENTX_PDU_ERROR_RESOURCEUNAVAILABLE:
- return "Resource unavailable";
- case AGENTX_PDU_ERROR_COMMITFAILED:
- return "Commit failed";
- case AGENTX_PDU_ERROR_UNDOFAILED:
- return "Undo failed";
- case AGENTX_PDU_ERROR_NOTWRITABLE:
- return "Not writable";
- case AGENTX_PDU_ERROR_INCONSISTENTNAME:
- return "Inconsistent name";
- case AGENTX_PDU_ERROR_OPENFAILED:
- return "Open Failed";
- case AGENTX_PDU_ERROR_NOTOPEN:
- return "Not open";
- case AGENTX_PDU_ERROR_INDEXWRONGTYPE:
- return "Index wrong type";
- case AGENTX_PDU_ERROR_INDEXALREADYALLOCATED:
- return "Index already allocated";
- case AGENTX_PDU_ERROR_INDEXNONEAVAILABLE:
- return "Index none available";
- case AGENTX_PDU_ERROR_INDEXNOTALLOCATED:
- return "Index not allocated";
- case AGENTX_PDU_ERROR_UNSUPPORTEDCONETXT:
- return "Unsupported context";
- case AGENTX_PDU_ERROR_DUPLICATEREGISTRATION:
- return "Duplicate registration";
- case AGENTX_PDU_ERROR_UNKNOWNREGISTRATION:
- return "Unkown registration";
- case AGENTX_PDU_ERROR_UNKNOWNAGENTCAPS:
- return "Unknown agent capabilities";
- case AGENTX_PDU_ERROR_PARSEERROR:
- return "Parse error";
- case AGENTX_PDU_ERROR_REQUESTDENIED:
- return "Request denied";
- case AGENTX_PDU_ERROR_PROCESSINGERROR:
- return "Processing error";
- }
- snprintf(buffer, sizeof(buffer), "Unknown error: %d", error);
- return buffer;
-}
-
-const char *
-agentx_pdutype2string(enum agentx_pdu_type type)
-{
- static char buffer[64];
- switch(type) {
- case AGENTX_PDU_TYPE_OPEN:
- return "agentx-Open-PDU";
- case AGENTX_PDU_TYPE_CLOSE:
- return "agentx-Close-PDU";
- case AGENTX_PDU_TYPE_REGISTER:
- return "agentx-Register-PDU";
- case AGENTX_PDU_TYPE_UNREGISTER:
- return "agentx-Unregister-PDU";
- case AGENTX_PDU_TYPE_GET:
- return "agentx-Get-PDU";
- case AGENTX_PDU_TYPE_GETNEXT:
- return "agentx-GetNext-PDU";
- case AGENTX_PDU_TYPE_GETBULK:
- return "agentx-GetBulk-PDU";
- case AGENTX_PDU_TYPE_TESTSET:
- return "agentx-TestSet-PDU";
- case AGENTX_PDU_TYPE_COMMITSET:
- return "agentx-CommitSet-PDU";
- case AGENTX_PDU_TYPE_UNDOSET:
- return "agentx-UndoSet-PDU";
- case AGENTX_PDU_TYPE_CLEANUPSET:
- return "agentx-CleanupSet-PDU";
- case AGENTX_PDU_TYPE_NOTIFY:
- return "agentx-Notify-PDU";
- case AGENTX_PDU_TYPE_PING:
- return "agentx-Ping-PDU";
- case AGENTX_PDU_TYPE_INDEXALLOCATE:
- return "agentx-IndexAllocate-PDU";
- case AGENTX_PDU_TYPE_INDEXDEALLOCATE:
- return "agentx-IndexDeallocate-PDU";
- case AGENTX_PDU_TYPE_ADDAGENTCAPS:
- return "agentx-AddAgentCaps-PDU";
- case AGENTX_PDU_TYPE_REMOVEAGENTCAPS:
- return "agentx-RemoveAgentCaps-PDU";
- case AGENTX_PDU_TYPE_RESPONSE:
- return "agentx-Response-PDU";
- }
- snprintf(buffer, sizeof(buffer), "Unknown type: %d", type);
- return buffer;
-}
-
-const char *
-agentx_closereason2string(enum agentx_close_reason reason)
-{
- static char buffer[64];
-
- switch (reason) {
- case AGENTX_CLOSE_OTHER:
- return "Undefined reason";
- case AGENTX_CLOSEN_PARSEERROR:
- return "Too many AgentX parse errors from peer";
- case AGENTX_CLOSE_PROTOCOLERROR:
- return "Too many AgentX protocol errors from peer";
- case AGENTX_CLOSE_TIMEOUTS:
- return "Too many timeouts waiting for peer";
- case AGENTX_CLOSE_SHUTDOWN:
- return "shutting down";
- case AGENTX_CLOSE_BYMANAGER:
- return "Manager shuts down";
- }
- snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason);
- return buffer;
-}
-
-const char *
-agentx_oid2string(struct agentx_oid *oid)
-{
- return agentx_oidrange2string(oid, 0, 0);
-}
-
-const char *
-agentx_oidrange2string(struct agentx_oid *oid, uint8_t range_subid,
- uint32_t upperbound)
-{
- static char buf[1024];
- char *p;
- size_t i, rest;
- int ret;
-
- rest = sizeof(buf);
- p = buf;
- for (i = 0; i < oid->aoi_idlen; i++) {
- if (range_subid != 0 && range_subid - 1 == (uint8_t)i)
- ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i],
- upperbound);
- else
- ret = snprintf(p, rest, ".%u", oid->aoi_id[i]);
- if ((size_t) ret >= rest) {
- snprintf(buf, sizeof(buf), "Couldn't parse oid");
- return buf;
+static int
+agentx_index_close_finalize(struct ax_pdu *pdu, void *cookie)
+{
+ struct agentx_index *axi = cookie;
+ struct agentx_region *axr = axi->axi_axr;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct ax_pdu_response *resp = &(pdu->ap_payload.ap_response);
+
+#ifdef AX_DEBUG
+ if (axi->axi_cstate != AX_CSTATE_WAITCLOSE)
+ agentx_log_axc_fatalx(axc, "%s: unexpected indexdeallocate",
+ __func__);
+#endif
+
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ agentx_log_axc_warnx(axc,
+ "index %s: couldn't deallocate: %s",
+ ax_oid2string(&(axi->axi_vb.avb_oid)),
+ ax_error2string(resp->ap_error));
+ agentx_reset(ax);
+ return -1;
+ }
+
+ if (resp->ap_nvarbind != 1) {
+ agentx_log_axc_warnx(axc,
+ "index %s: unexpected number of indices",
+ ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
+ return -1;
+ }
+ if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
+ agentx_log_axc_warnx(axc, "index %s: unexpected index type",
+ ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
+ return -1;
+ }
+ if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
+ &(axi->axi_vb.avb_oid)) != 0) {
+ agentx_log_axc_warnx(axc, "index %s: unexpected oid",
+ ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
+ return -1;
+ }
+ switch (axi->axi_vb.avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+ if (axi->axi_vb.avb_data.avb_uint32 !=
+ resp->ap_varbindlist[0].avb_data.avb_uint32) {
+ agentx_log_axc_warnx(axc,
+ "index %s: unexpected index value",
+ ax_oid2string(&(axr->axr_oid)));
+ agentx_reset(ax);
+ return -1;
}
- p += ret;
- rest -= (size_t) ret;
+ break;
+ default:
+ agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
+ __func__);
+ }
+
+ axi->axi_cstate = AX_CSTATE_CLOSE;
+
+ agentx_log_axc_info(axc, "index %s: deallocated",
+ ax_oid2string(&(axi->axi_vb.avb_oid)));
+
+ if (axi->axi_dstate == AX_DSTATE_CLOSE) {
+ agentx_index_free_finalize(axi);
+ } else if (axr->axr_cstate == AX_CSTATE_OPEN) {
+ if (agentx_index_start(axi) == -1)
+ return -1;
}
- return buf;
+ return 0;
}
-const char *
-agentx_varbind2string(struct agentx_varbind *vb)
+struct agentx_object *
+agentx_object(struct agentx_region *axr, uint32_t oid[], size_t oidlen,
+ struct agentx_index *axi[], size_t axilen, int implied,
+ void (*get)(struct agentx_varbind *))
{
- static char buf[1024];
- char tmpbuf[1024];
- size_t i, bufleft;
- int ishex = 0;
- char *p;
- int ret;
+ struct agentx_object *axo, **tsao, axo_search;
+ struct agentx_index *lsai;
+ int ready = 1;
+ size_t i, j;
+
+ if (axr->axr_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
+ __func__);
+ if (oidlen < 1) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen == 0",
+ __func__);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen == 0",
+ __func__);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+ if (oidlen > AGENTX_OID_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: oidlen > %d",
+ __func__, AGENTX_OID_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+ if (axilen > AGENTX_OID_INDEX_MAX_LEN) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: indexlen > %d",
+ __func__, AGENTX_OID_INDEX_MAX_LEN);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: indexlen > %d",
+ __func__, AGENTX_OID_INDEX_MAX_LEN);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
- switch (vb->avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
- snprintf(buf, sizeof(buf), "%s: (int)%u",
- agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
- break;
- case AGENTX_DATA_TYPE_OCTETSTRING:
- for (i = 0;
- i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) {
- if (!isprint(vb->avb_data.avb_ostring.aos_string[i]))
- ishex = 1;
+ for (i = 0; i < oidlen; i++)
+ axo_search.axo_oid.aoi_id[i] = oid[i];
+ axo_search.axo_oid.aoi_idlen = oidlen;
+
+ do {
+ if (RB_FIND(axc_objects, &(axr->axr_axc->axc_objects),
+ &axo_search) != NULL) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid "
+ "parent child object relationship", __func__);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: invalid "
+ "parent child object relationship", __func__);
+ errno = EINVAL;
+ return NULL;
+#endif
}
- if (ishex) {
- p = tmpbuf;
- bufleft = sizeof(tmpbuf);
- for (i = 0;
- i < vb->avb_data.avb_ostring.aos_slen; i++) {
- ret = snprintf(p, bufleft, " %02hhX",
- vb->avb_data.avb_ostring.aos_string[i]);
- if (ret >= (int) bufleft) {
- p = strrchr(p, ' ');
- strlcpy(p, "...", 4);
- break;
- }
- p += 3;
- bufleft -= 3;
+ axo_search.axo_oid.aoi_idlen--;
+ } while (axo_search.axo_oid.aoi_idlen > 0);
+ axo_search.axo_oid.aoi_idlen = oidlen;
+ axo = RB_NFIND(axc_objects, &(axr->axr_axc->axc_objects), &axo_search);
+ if (axo != NULL &&
+ ax_oid_cmp(&(axo->axo_oid), &(axo_search.axo_oid)) == 2) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid parent "
+ "child object relationship", __func__);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: invalid parent "
+ "child object relationship", __func__);
+ errno = EINVAL;
+ return NULL;
+#endif
+ }
+ if (implied == 1) {
+ lsai = axi[axilen - 1];
+ if (lsai->axi_vb.avb_type == AX_DATA_TYPE_OCTETSTRING) {
+ if (lsai->axi_vb.avb_data.avb_ostring.aos_slen != 0) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc,
+ "%s: implied can only be used on strings "
+ "of dynamic length", __func__);
+#else
+ agentx_log_axc_warnx(axr->axr_axc,
+ "%s: implied can only be used on strings "
+ "of dynamic length", __func__);
+ errno = EINVAL;
+ return NULL;
+#endif
}
- ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s",
- agentx_oid2string(&(vb->avb_oid)), tmpbuf);
- if (ret >= (int) sizeof(buf)) {
- p = strrchr(buf, ' ');
- strlcpy(p, "...", 4);
+ } else if (lsai->axi_vb.avb_type == AX_DATA_TYPE_OID) {
+ if (lsai->axi_vb.avb_data.avb_oid.aoi_idlen != 0) {
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc,
+ "%s: implied can only be used on oids of "
+ "dynamic length", __func__);
+#else
+ agentx_log_axc_warnx(axr->axr_axc,
+ "%s: implied can only be used on oids of "
+ "dynamic length", __func__);
+ errno = EINVAL;
+ return NULL;
+#endif
}
} else {
- ret = snprintf(buf, sizeof(buf), "%s: (string)",
- agentx_oid2string(&(vb->avb_oid)));
- if (ret >= (int) sizeof(buf)) {
- snprintf(buf, sizeof(buf), "<too large OID>: "
- "(string)<too large string>");
- break;
- }
- p = buf + ret;
- bufleft = (int) sizeof(buf) - ret;
- if (snprintf(p, bufleft, "%.*s",
- vb->avb_data.avb_ostring.aos_slen,
- vb->avb_data.avb_ostring.aos_string) >=
- (int) bufleft) {
- p = buf + sizeof(buf) - 4;
- strlcpy(p, "...", 4);
- }
- }
- break;
- case AGENTX_DATA_TYPE_NULL:
- snprintf(buf, sizeof(buf), "%s: <null>",
- agentx_oid2string(&(vb->avb_oid)));
- break;
- case AGENTX_DATA_TYPE_OID:
- strlcpy(tmpbuf,
- agentx_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf));
- snprintf(buf, sizeof(buf), "%s: (oid)%s",
- agentx_oid2string(&(vb->avb_oid)), tmpbuf);
- break;
- case AGENTX_DATA_TYPE_IPADDRESS:
- if (vb->avb_data.avb_ostring.aos_slen != 4) {
- snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>",
- agentx_oid2string(&(vb->avb_oid)));
- break;
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axr->axr_axc, "%s: implied "
+ "can only be set on oid and string indices",
+ __func__);
+#else
+ agentx_log_axc_warnx(axr->axr_axc, "%s: implied can "
+ "only be set on oid and string indices", __func__);
+ errno = EINVAL;
+ return NULL;
+#endif
}
- if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string,
- tmpbuf, sizeof(tmpbuf)) == NULL) {
- snprintf(buf, sizeof(buf), "%s: (ipaddress)"
- "<unparseable>: %s",
- agentx_oid2string(&(vb->avb_oid)),
- strerror(errno));
- break;
+ }
+
+ ready = axr->axr_cstate == AX_CSTATE_OPEN;
+ if ((axo = calloc(1, sizeof(*axo))) == NULL)
+ return NULL;
+ axo->axo_axr = axr;
+ bcopy(&(axo_search.axo_oid), &(axo->axo_oid), sizeof(axo->axo_oid));
+ for (i = 0; i < axilen; i++) {
+ axo->axo_index[i] = axi[i];
+ if (axi[i]->axi_objectlen == axi[i]->axi_objectsize) {
+ tsao = recallocarray(axi[i]->axi_object,
+ axi[i]->axi_objectlen, axi[i]->axi_objectlen + 1,
+ sizeof(*axi[i]->axi_object));
+ if (tsao == NULL) {
+ free(axo);
+ return NULL;
+ }
+ axi[i]->axi_object = tsao;
+ axi[i]->axi_objectsize = axi[i]->axi_objectlen + 1;
}
- snprintf(buf, sizeof(buf), "%s: (ipaddress)%s",
- agentx_oid2string(&(vb->avb_oid)), tmpbuf);
- break;
- case AGENTX_DATA_TYPE_COUNTER32:
- snprintf(buf, sizeof(buf), "%s: (counter32)%u",
- agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
- break;
- case AGENTX_DATA_TYPE_GAUGE32:
- snprintf(buf, sizeof(buf), "%s: (gauge32)%u",
- agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
- break;
- case AGENTX_DATA_TYPE_TIMETICKS:
- snprintf(buf, sizeof(buf), "%s: (timeticks)%u",
- agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
- break;
- case AGENTX_DATA_TYPE_OPAQUE:
- p = tmpbuf;
- bufleft = sizeof(tmpbuf);
- for (i = 0;
- i < vb->avb_data.avb_ostring.aos_slen; i++) {
- ret = snprintf(p, bufleft, " %02hhX",
- vb->avb_data.avb_ostring.aos_string[i]);
- if (ret >= (int) bufleft) {
- p = strrchr(p, ' ');
- strlcpy(p, "...", 4);
+ for (j = 0; j < axi[i]->axi_objectlen; j++) {
+ if (ax_oid_cmp(&(axo->axo_oid),
+ &(axi[i]->axi_object[j]->axo_oid)) < 0) {
+ memmove(&(axi[i]->axi_object[j + 1]),
+ &(axi[i]->axi_object[j]),
+ sizeof(*(axi[i]->axi_object)) *
+ (axi[i]->axi_objectlen - j));
break;
}
- p += 3;
- bufleft -= 3;
}
- ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s",
- agentx_oid2string(&(vb->avb_oid)), tmpbuf);
- if (ret >= (int) sizeof(buf)) {
- p = strrchr(buf, ' ');
- strlcpy(p, "...", 4);
+ axi[i]->axi_object[j] = axo;
+ axi[i]->axi_objectlen++;
+ if (axi[i]->axi_cstate != AX_CSTATE_OPEN)
+ ready = 0;
+ }
+ axo->axo_indexlen = axilen;
+ axo->axo_implied = implied;
+ axo->axo_timeout = 0;
+ axo->axo_lock = 0;
+ axo->axo_get = get;
+ axo->axo_cstate = AX_CSTATE_CLOSE;
+ axo->axo_dstate = AX_DSTATE_OPEN;
+
+ TAILQ_INSERT_TAIL(&(axr->axr_objects), axo, axo_axr_objects);
+ RB_INSERT(axc_objects, &(axr->axr_axc->axc_objects), axo);
+
+ if (ready)
+ agentx_object_start(axo);
+
+ return axo;
+}
+
+static int
+agentx_object_start(struct agentx_object *axo)
+{
+ struct agentx_region *axr = axo->axo_axr;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct ax_oid oid;
+ char oids[1024];
+ size_t i;
+ int needregister = 0;
+ uint32_t packetid;
+ uint8_t flags = AX_PDU_FLAG_INSTANCE_REGISTRATION;
+
+#ifdef AX_DEBUG
+ if (axr->axr_cstate != AX_CSTATE_OPEN ||
+ axo->axo_cstate != AX_CSTATE_CLOSE ||
+ axo->axo_dstate != AX_DSTATE_OPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: unexpected object registration", __func__);
+#endif
+
+ if (axo->axo_timeout != 0)
+ needregister = 1;
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
+ return 0;
+ if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
+ needregister = 1;
+ }
+ if (!needregister) {
+ axo->axo_cstate = AX_CSTATE_WAITOPEN;
+ agentx_object_finalize(NULL, axo);
+ return 0;
+ }
+
+ bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
+ flags = 0;
+ break;
}
- break;
- case AGENTX_DATA_TYPE_COUNTER64:
- snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64,
- agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64);
- break;
- case AGENTX_DATA_TYPE_NOSUCHOBJECT:
- snprintf(buf, sizeof(buf), "%s: <noSuchObject>",
- agentx_oid2string(&(vb->avb_oid)));
- break;
- case AGENTX_DATA_TYPE_NOSUCHINSTANCE:
- snprintf(buf, sizeof(buf), "%s: <noSuchInstance>",
- agentx_oid2string(&(vb->avb_oid)));
- break;
- case AGENTX_DATA_TYPE_ENDOFMIBVIEW:
- snprintf(buf, sizeof(buf), "%s: <endOfMibView>",
- agentx_oid2string(&(vb->avb_oid)));
- break;
+#ifdef AX_DEBUG
+ if (axo->axo_index[i]->axi_vb.avb_type !=
+ AX_DATA_TYPE_INTEGER)
+ agentx_log_axc_fatalx(axc,
+ "%s: Unsupported allocated index type", __func__);
+#endif
+ oid.aoi_id[oid.aoi_idlen++] =
+ axo->axo_index[i]->axi_vb.avb_data.avb_uint32;
+ }
+ packetid = ax_register(ax->ax_ax, flags, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), axo->axo_timeout,
+ AX_PRIORITY_DEFAULT, 0, &oid, 0);
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_REGISTER));
+ agentx_reset(ax);
+ return -1;
}
- return buf;
+ strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
+ agentx_log_axc_info(axc, "object %s (%s %s): opening",
+ oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
+ axo->axo_cstate = AX_CSTATE_WAITOPEN;
+ return agentx_request(ax, packetid, agentx_object_finalize, axo);
}
-int
-agentx_oid_cmp(struct agentx_oid *o1, struct agentx_oid *o2)
+static int
+agentx_object_finalize(struct ax_pdu *pdu, void *cookie)
{
- size_t i, min;
+ struct agentx_object *axo = cookie;
+ struct agentx_context *axc = axo->axo_axr->axr_axc;
+ struct ax_oid oid;
+ char oids[1024];
+ size_t i;
+ uint8_t flags = 1;
+
+#ifdef AX_DEBUG
+ if (axo->axo_cstate != AX_CSTATE_WAITOPEN)
+ agentx_log_axc_fatalx(axc, "%s: not expecting object open",
+ __func__);
+#endif
+
+ if (pdu == NULL) {
+ axo->axo_cstate = AX_CSTATE_OPEN;
+ return 0;
+ }
+
+ bcopy(&(axo->axo_oid), &oid, sizeof(oid));
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
+ flags = 0;
+ break;
+ }
+#ifdef AX_DEBUG
+ if (axo->axo_index[i]->axi_vb.avb_type !=
+ AX_DATA_TYPE_INTEGER)
+ agentx_log_axc_fatalx(axc,
+ "%s: Unsupported allocated index type", __func__);
+#endif
+
+ oid.aoi_id[oid.aoi_idlen++] =
+ axo->axo_index[i]->axi_vb.avb_data.avb_uint32;
+ }
+ strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
+
+ /*
+ * We should only be here for table objects with registered indices.
+ * If we fail here something is misconfigured and the admin should fix
+ * it.
+ */
+ if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
+ axo->axo_cstate = AX_CSTATE_CLOSE;
+ agentx_log_axc_info(axc, "object %s (%s %s): %s",
+ oids, flags ? "instance" : "region", ax_oid2string(&oid),
+ ax_error2string(pdu->ap_payload.ap_response.ap_error));
+ if (axo->axo_dstate == AX_DSTATE_CLOSE)
+ return agentx_object_close_finalize(NULL, axo);
+ return 0;
+ }
+ axo->axo_cstate = AX_CSTATE_OPEN;
+ agentx_log_axc_info(axc, "object %s (%s %s): open", oids,
+ flags ? "instance" : "region", ax_oid2string(&oid));
+
+ if (axo->axo_dstate == AX_DSTATE_CLOSE)
+ return agentx_object_close(axo);
- min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen;
- for (i = 0; i < min; i++) {
- if (o1->aoi_id[i] < o2->aoi_id[i])
- return -1;
- if (o1->aoi_id[i] > o2->aoi_id[i])
- return 1;
- }
- /* o1 is parent of o2 */
- if (o1->aoi_idlen < o2->aoi_idlen)
- return -2;
- /* o1 is child of o2 */
- if (o1->aoi_idlen > o2->aoi_idlen)
- return 2;
return 0;
}
-int
-agentx_oid_add(struct agentx_oid *oid, uint32_t value)
+static int
+agentx_object_lock(struct agentx_object *axo)
{
- if (oid->aoi_idlen == AGENTX_OID_MAX_LEN)
+ if (axo->axo_lock == UINT32_MAX) {
+ agentx_log_axc_warnx(axo->axo_axr->axr_axc,
+ "%s: axo_lock == %u", __func__, UINT32_MAX);
return -1;
- oid->aoi_id[oid->aoi_idlen++] = value;
+ }
+ axo->axo_lock++;
return 0;
}
-static uint32_t
-agentx_pdu_queue(struct agentx *ax)
+static void
+agentx_object_unlock(struct agentx_object *axo)
{
- struct agentx_pdu_header header;
- uint32_t packetid, plength;
- size_t wbtlen = ax->ax_wbtlen;
+#ifdef AX_DEBUG
+ if (axo->axo_lock == 0)
+ agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
+ "%s: axo_lock == 0", __func__);
+#endif
+ axo->axo_lock--;
+ if (axo->axo_lock == 0 && axo->axo_dstate == AX_DSTATE_CLOSE &&
+ axo->axo_cstate == AX_CSTATE_CLOSE)
+ agentx_object_free_finalize(axo);
+}
- header.aph_flags = ax->ax_byteorder == AGENTX_BYTE_ORDER_BE ?
- AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER : 0;
- packetid = agentx_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12]));
- plength = (ax->ax_wbtlen - ax->ax_wblen) - AGENTX_PDU_HEADER;
- ax->ax_wbtlen = ax->ax_wblen + 16;
- (void)agentx_pdu_add_uint32(ax, plength);
+static int
+agentx_object_close(struct agentx_object *axo)
+{
+ struct agentx_context *axc = axo->axo_axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct ax_oid oid;
+ char oids[1024];
+ size_t i;
+ int needclose = 0;
+ uint32_t packetid;
+ uint8_t flags = 1;
+
+#ifdef AX_DEBUG
+ if (axo->axo_cstate != AX_CSTATE_OPEN)
+ agentx_log_axc_fatalx(axc, "%s: unexpected object close",
+ __func__);
+#endif
- ax->ax_wblen = ax->ax_wbtlen = wbtlen;
+ for (i = 0; i < axo->axo_indexlen; i++) {
+#ifdef AX_DEBUG
+ if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
+ agentx_log_axc_fatalx(axc,
+ "%s: Object open while index closed", __func__);
+#endif
+ if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
+ needclose = 1;
+ }
+ axo->axo_cstate = AX_CSTATE_WAITCLOSE;
+ if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
+ return 0;
+ if (!needclose) {
+ agentx_object_close_finalize(NULL, axo);
+ return 0;
+ }
- return packetid;
+ bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
+ flags = 0;
+ break;
+ }
+#ifdef AX_DEBUG
+ if (axo->axo_index[i]->axi_vb.avb_type !=
+ AX_DATA_TYPE_INTEGER)
+ agentx_log_axc_fatalx(axc,
+ "%s: Unsupported allocated index type", __func__);
+#endif
+ oid.aoi_id[oid.aoi_idlen++] =
+ axo->axo_index[i]->axi_vb.avb_data.avb_uint32;
+ }
+ packetid = ax_unregister(ax->ax_ax, axs->axs_id,
+ AGENTX_CONTEXT_CTX(axc), AX_PRIORITY_DEFAULT, 0, &oid, 0);
+ if (packetid == 0) {
+ agentx_log_axc_warn(axc, "couldn't generate %s",
+ ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
+ agentx_reset(ax);
+ return -1;
+ }
+ strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
+ agentx_log_axc_info(axc, "object %s (%s %s): closing",
+ oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
+ return agentx_request(ax, packetid, agentx_object_close_finalize,
+ axo);
}
static int
-agentx_pdu_header(struct agentx *ax, enum agentx_pdu_type type, uint8_t flags,
- uint32_t sessionid, uint32_t transactionid, uint32_t packetid,
- struct agentx_ostring *context)
+agentx_object_close_finalize(struct ax_pdu *pdu, void *cookie)
{
- if (ax->ax_wblen != ax->ax_wbtlen) {
- errno = EALREADY;
- return -1;
- }
+ struct agentx_object *axo = cookie;
+ struct agentx_region *axr = axo->axo_axr;
+ struct agentx_context *axc = axr->axr_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct ax_oid oid;
+ char oids[1024];
+ uint8_t flags = 1;
+ size_t i;
- ax->ax_wbtlen = ax->ax_wblen;
- if (agentx_pdu_need(ax, 4) == -1)
- return -1;
- ax->ax_wbuf[ax->ax_wbtlen++] = 1;
- ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type;
- if (context != NULL)
- flags |= AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT;
- if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE)
- flags |= AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER;
- ax->ax_wbuf[ax->ax_wbtlen++] = flags;
- ax->ax_wbuf[ax->ax_wbtlen++] = 0;
- if (packetid == 0)
- packetid = agentx_packetid(ax);
- if (agentx_pdu_add_uint32(ax, sessionid) == -1 ||
- agentx_pdu_add_uint32(ax, transactionid) == -1 ||
- agentx_pdu_add_uint32(ax, packetid) == -1 ||
- agentx_pdu_need(ax, 4) == -1)
- return -1;
- ax->ax_wbtlen += 4;
- if (context != NULL) {
- if (agentx_pdu_add_str(ax, context) == -1)
+#ifdef AX_DEBUG
+ if (axo->axo_cstate != AX_CSTATE_WAITCLOSE)
+ agentx_log_axc_fatalx(axc,
+ "%s: unexpected object unregister", __func__);
+#endif
+
+ if (pdu != NULL) {
+ bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
+ flags = 0;
+ break;
+ }
+#ifdef AX_DEBUG
+ if (axo->axo_index[i]->axi_vb.avb_type !=
+ AX_DATA_TYPE_INTEGER)
+ agentx_log_axc_fatalx(axc,
+ "%s: Unsupported allocated index type",
+ __func__);
+#endif
+ oid.aoi_id[oid.aoi_idlen++] =
+ axo->axo_index[i]->axi_vb.avb_data.avb_uint32;
+ }
+ strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
+ if (pdu->ap_payload.ap_response.ap_error !=
+ AX_PDU_ERROR_NOERROR) {
+ agentx_log_axc_warnx(axc,
+ "closing object %s (%s %s): %s", oids,
+ flags ? "instance" : "region",
+ ax_oid2string(&oid), ax_error2string(
+ pdu->ap_payload.ap_response.ap_error));
+ agentx_reset(ax);
return -1;
+ }
+ agentx_log_axc_info(axc, "object %s (%s %s): closed", oids,
+ flags ? "instance" : "region", ax_oid2string(&oid));
+ }
+
+ if (axo->axo_dstate == AX_DSTATE_CLOSE)
+ agentx_object_free_finalize(axo);
+ else {
+ if (axr->axr_cstate == AX_CSTATE_OPEN)
+ if (agentx_object_start(axo) == -1)
+ return -1;
}
return 0;
}
-static uint32_t
-agentx_packetid(struct agentx *ax)
+void
+agentx_object_free(struct agentx_object *axo)
+{
+ if (axo == NULL)
+ return;
+
+ if (axo->axo_dstate == AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
+ "%s: double free", __func__);
+
+ axo->axo_dstate = AX_DSTATE_CLOSE;
+
+ if (axo->axo_cstate == AX_CSTATE_OPEN) {
+ if (agentx_object_close(axo) == -1)
+ return;
+ }
+ if (axo->axo_cstate == AX_CSTATE_CLOSE)
+ agentx_object_free_finalize(axo);
+}
+
+static void
+agentx_object_free_finalize(struct agentx_object *axo)
{
- uint32_t packetid, *packetids;
- size_t npackets = 0, i;
+#ifdef AX_DEBUG
+ struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
+#endif
+ size_t i, j;
int found;
- if (ax->ax_packetids != NULL) {
- for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++)
- continue;
+#ifdef AX_DEBUG
+ if (axo->axo_dstate != AX_DSTATE_CLOSE)
+ agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
+ "%s: unexpected free", __func__);
+#endif
+
+ if (axo->axo_lock != 0) {
+#ifdef AX_DEBUG
+ if (TAILQ_EMPTY(&(ax->ax_getreqs)))
+ agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
+ "%s: %s axo_lock == %u", __func__,
+ ax_oid2string(&(axo->axo_oid)), axo->axo_lock);
+#endif
+ return;
}
- if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) {
- packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize,
- ax->ax_packetidsize + 25, sizeof(*packetids));
- if (packetids == NULL)
+
+ RB_REMOVE(axc_objects, &(axo->axo_axr->axr_axc->axc_objects), axo);
+ TAILQ_REMOVE(&(axo->axo_axr->axr_objects), axo, axo_axr_objects);
+
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ found = 0;
+ for (j = 0; j < axo->axo_index[i]->axi_objectlen; j++) {
+ if (axo->axo_index[i]->axi_object[j] == axo)
+ found = 1;
+ if (found && j + 1 != axo->axo_index[i]->axi_objectlen)
+ axo->axo_index[i]->axi_object[j] =
+ axo->axo_index[i]->axi_object[j + 1];
+ }
+#ifdef AX_DEBUG
+ if (!found)
+ agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
+ "%s: object not found in index", __func__);
+#endif
+ axo->axo_index[i]->axi_objectlen--;
+ if (axo->axo_index[i]->axi_dstate == AX_DSTATE_CLOSE &&
+ axo->axo_index[i]->axi_cstate == AX_CSTATE_CLOSE)
+ agentx_index_free_finalize(axo->axo_index[i]);
+ }
+
+ free(axo);
+}
+
+static void
+agentx_object_reset(struct agentx_object *axo)
+{
+ axo->axo_cstate = AX_CSTATE_CLOSE;
+
+ if (axo->axo_dstate == AX_DSTATE_CLOSE)
+ agentx_object_free_finalize(axo);
+}
+
+static int
+agentx_object_cmp(struct agentx_object *o1, struct agentx_object *o2)
+{
+ return ax_oid_cmp(&(o1->axo_oid), &(o2->axo_oid));
+}
+
+static int
+agentx_object_implied(struct agentx_object *axo,
+ struct agentx_index *axi)
+{
+ size_t i = 0;
+
+ for (i = 0; i < axo->axo_indexlen; i++) {
+ if (axo->axo_index[i] == axi) {
+ if (axi->axi_vb.avb_data.avb_ostring.aos_slen != 0)
+ return 1;
+ else if (i == axo->axo_indexlen - 1)
+ return axo->axo_implied;
return 0;
- ax->ax_packetidsize += 25;
- ax->ax_packetids = packetids;
+ }
}
+#ifdef AX_DEBUG
+ agentx_log_axc_fatalx(axo->axo_axr->axr_axc, "%s: unsupported index",
+ __func__);
+#endif
+ return 0;
+}
+
+static void
+agentx_get_start(struct agentx_context *axc, struct ax_pdu *pdu)
+{
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ struct agentx_get *axg, tsag;
+ struct ax_pdu_searchrangelist *srl;
+ char *logmsg = NULL;
+ size_t i, j;
+ int fail = 0;
+
+ if ((axg = calloc(1, sizeof(*axg))) == NULL) {
+ tsag.axg_sessionid = pdu->ap_header.aph_sessionid;
+ tsag.axg_transactionid = pdu->ap_header.aph_transactionid;
+ tsag.axg_packetid = pdu->ap_header.aph_packetid;
+ tsag.axg_context_default = axc->axc_name_default;
+ tsag.axg_fd = axc->axc_axs->axs_ax->ax_fd;
+ agentx_log_axg_warn(&tsag, "Couldn't parse request");
+ agentx_reset(ax);
+ return;
+ }
+
+ axg->axg_sessionid = pdu->ap_header.aph_sessionid;
+ axg->axg_transactionid = pdu->ap_header.aph_transactionid;
+ axg->axg_packetid = pdu->ap_header.aph_packetid;
+ axg->axg_context_default = axc->axc_name_default;
+ axg->axg_fd = axc->axc_axs->axs_ax->ax_fd;
+ if (!axc->axc_name_default) {
+ axg->axg_context.aos_string =
+ (unsigned char *)strdup((char *)axc->axc_name.aos_string);
+ if (axg->axg_context.aos_string == NULL) {
+ agentx_log_axg_warn(axg, "Couldn't parse request");
+ free(axg);
+ agentx_reset(ax);
+ return;
+ }
+ }
+ axg->axg_context.aos_slen = axc->axc_name.aos_slen;
+ axg->axg_type = pdu->ap_header.aph_type;
+ axg->axg_axc = axc;
+ TAILQ_INSERT_TAIL(&(ax->ax_getreqs), axg, axg_ax_getreqs);
+ if (axg->axg_type == AX_PDU_TYPE_GET ||
+ axg->axg_type == AX_PDU_TYPE_GETNEXT) {
+ srl = &(pdu->ap_payload.ap_srl);
+ axg->axg_nvarbind = srl->ap_nsr;
+ } else {
+ axg->axg_nonrep = pdu->ap_payload.ap_getbulk.ap_nonrep;
+ axg->axg_maxrep = pdu->ap_payload.ap_getbulk.ap_maxrep;
+ srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
+ axg->axg_nvarbind = ((srl->ap_nsr - axg->axg_nonrep) *
+ axg->axg_maxrep) + axg->axg_nonrep;
+ }
+
+ if ((axg->axg_varbind = calloc(axg->axg_nvarbind,
+ sizeof(*(axg->axg_varbind)))) == NULL) {
+ agentx_log_axg_warn(axg, "Couldn't parse request");
+ agentx_get_free(axg);
+ agentx_reset(ax);
+ return;
+ }
+
+ /* XXX net-snmp doesn't use getbulk, so untested */
+ /* Two loops: varbind after needs to be initialized */
+ for (i = 0; i < srl->ap_nsr; i++) {
+ if (i < axg->axg_nonrep ||
+ axg->axg_type != AX_PDU_TYPE_GETBULK)
+ j = i;
+ else if (axg->axg_maxrep == 0)
+ break;
+ else
+ j = (axg->axg_maxrep * i) + axg->axg_nonrep;
+ bcopy(&(srl->ap_sr[i].asr_start),
+ &(axg->axg_varbind[j].axv_vb.avb_oid),
+ sizeof(srl->ap_sr[i].asr_start));
+ bcopy(&(srl->ap_sr[i].asr_start),
+ &(axg->axg_varbind[j].axv_start),
+ sizeof(srl->ap_sr[i].asr_start));
+ bcopy(&(srl->ap_sr[i].asr_stop),
+ &(axg->axg_varbind[j].axv_end),
+ sizeof(srl->ap_sr[i].asr_stop));
+ axg->axg_varbind[j].axv_initialized = 1;
+ axg->axg_varbind[j].axv_axg = axg;
+ axg->axg_varbind[j].axv_include =
+ srl->ap_sr[i].asr_start.aoi_include;
+ if (j == 0)
+ fail |= agentx_strcat(&logmsg, " {");
+ else
+ fail |= agentx_strcat(&logmsg, ",{");
+ fail |= agentx_strcat(&logmsg,
+ ax_oid2string(&(srl->ap_sr[i].asr_start)));
+ if (srl->ap_sr[i].asr_start.aoi_include)
+ fail |= agentx_strcat(&logmsg, " (inclusive)");
+ if (srl->ap_sr[i].asr_stop.aoi_idlen != 0) {
+ fail |= agentx_strcat(&logmsg, " - ");
+ fail |= agentx_strcat(&logmsg,
+ ax_oid2string(&(srl->ap_sr[i].asr_stop)));
+ }
+ fail |= agentx_strcat(&logmsg, "}");
+ if (fail) {
+ agentx_log_axg_warn(axg, "Couldn't parse request");
+ free(logmsg);
+ agentx_get_free(axg);
+ agentx_reset(ax);
+ return;
+ }
+ }
+
+ agentx_log_axg_debug(axg, "%s:%s",
+ ax_pdutype2string(axg->axg_type), logmsg);
+ free(logmsg);
+
+ for (i = 0; i < srl->ap_nsr; i++) {
+ if (i < axg->axg_nonrep ||
+ axg->axg_type != AX_PDU_TYPE_GETBULK)
+ j = i;
+ else if (axg->axg_maxrep == 0)
+ break;
+ else
+ j = (axg->axg_maxrep * i) + axg->axg_nonrep;
+ agentx_varbind_start(&(axg->axg_varbind[j]));
+ }
+}
+
+static void
+agentx_get_finalize(struct agentx_get *axg)
+{
+ struct agentx_context *axc = axg->axg_axc;
+ struct agentx_session *axs = axc->axc_axs;
+ struct agentx *ax = axs->axs_ax;
+ size_t i, j, nvarbind = 0;
+ uint16_t error = 0, index = 0;
+ struct ax_varbind *vbl;
+ char *logmsg = NULL;
+ int fail = 0;
+
+ for (i = 0; i < axg->axg_nvarbind; i++) {
+ if (axg->axg_varbind[i].axv_initialized) {
+ if (axg->axg_varbind[i].axv_vb.avb_type == 0)
+ return;
+ nvarbind++;
+ }
+ }
+
+ if (axg->axg_axc == NULL) {
+ agentx_get_free(axg);
+ return;
+ }
+
+ if ((vbl = calloc(nvarbind, sizeof(*vbl))) == NULL) {
+ agentx_log_axg_warn(axg, "Couldn't parse request");
+ agentx_get_free(axg);
+ agentx_reset(ax);
+ return;
+ }
+ for (i = 0, j = 0; i < axg->axg_nvarbind; i++) {
+ if (axg->axg_varbind[i].axv_initialized) {
+ memcpy(&(vbl[j]), &(axg->axg_varbind[i].axv_vb),
+ sizeof(*vbl));
+ if (error == 0 && axg->axg_varbind[i].axv_error !=
+ AX_PDU_ERROR_NOERROR) {
+ error = axg->axg_varbind[i].axv_error;
+ index = j + 1;
+ }
+ if (j == 0)
+ fail |= agentx_strcat(&logmsg, " {");
+ else
+ fail |= agentx_strcat(&logmsg, ",{");
+ fail |= agentx_strcat(&logmsg,
+ ax_varbind2string(&(vbl[j])));
+ if (axg->axg_varbind[i].axv_error !=
+ AX_PDU_ERROR_NOERROR) {
+ fail |= agentx_strcat(&logmsg, "(");
+ fail |= agentx_strcat(&logmsg,
+ ax_error2string(
+ axg->axg_varbind[i].axv_error));
+ fail |= agentx_strcat(&logmsg, ")");
+ }
+ fail |= agentx_strcat(&logmsg, "}");
+ if (fail) {
+ agentx_log_axg_warn(axg,
+ "Couldn't parse request");
+ free(logmsg);
+ agentx_get_free(axg);
+ return;
+ }
+ j++;
+ }
+ }
+ agentx_log_axg_debug(axg, "response:%s", logmsg);
+ free(logmsg);
+
+ if (ax_response(ax->ax_ax, axs->axs_id, axg->axg_transactionid,
+ axg->axg_packetid, AGENTX_CONTEXT_CTX(axc), 0, error, index,
+ vbl, nvarbind) == -1) {
+ agentx_log_axg_warn(axg, "Couldn't parse request");
+ agentx_reset(ax);
+ } else
+ agentx_wantwrite(ax, ax->ax_fd);
+ free(vbl);
+ agentx_get_free(axg);
+}
+
+void
+agentx_get_free(struct agentx_get *axg)
+{
+ struct agentx_varbind *axv;
+ struct agentx_object *axo;
+ struct agentx *ax = axg->axg_axc->axc_axs->axs_ax;
+ struct agentx_varbind_index *index;
+ size_t i, j;
+
+ if (axg->axg_axc != NULL)
+ TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
+
+ for (i = 0; i < axg->axg_nvarbind; i++) {
+ axv = &(axg->axg_varbind[i]);
+ for (j = 0; axv->axv_axo != NULL &&
+ j < axv->axv_axo->axo_indexlen; j++) {
+ axo = axv->axv_axo;
+ index = &(axv->axv_index[j]);
+ if (axo->axo_index[j]->axi_vb.avb_type ==
+ AX_DATA_TYPE_OCTETSTRING ||
+ axo->axo_index[j]->axi_vb.avb_type ==
+ AX_DATA_TYPE_IPADDRESS)
+ free(index->axv_idata.avb_ostring.aos_string);
+ }
+ ax_varbind_free(&(axg->axg_varbind[i].axv_vb));
+ }
+
+ free(axg->axg_context.aos_string);
+ free(axg->axg_varbind);
+ free(axg);
+}
+
+static void
+agentx_varbind_start(struct agentx_varbind *axv)
+{
+ struct agentx_get *axg = axv->axv_axg;
+ struct agentx_context *axc = axg->axg_axc;
+ struct agentx_object *axo, axo_search;
+ struct agentx_varbind_index *index;
+ struct agentx_index *axi;
+ struct ax_oid *oid;
+ union ax_data *data;
+ struct in_addr *ipaddress;
+ unsigned char *ipbytes;
+ size_t i, j, k;
+ int overflow = 0, dynamic;
+
+#ifdef AX_DEBUG
+ if (!axv->axv_initialized)
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "%s: axv_initialized not set", __func__);
+#endif
+
+ bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
+ sizeof(axo_search.axo_oid));
+
do {
- found = 0;
- packetid = arc4random();
- for (i = 0; ax->ax_packetids[i] != 0; i++) {
- if (ax->ax_packetids[i] == packetid) {
- found = 1;
+ axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
+ if (axo_search.axo_oid.aoi_idlen > 0)
+ axo_search.axo_oid.aoi_idlen--;
+ } while (axo == NULL && axo_search.axo_oid.aoi_idlen > 0);
+ if (axo == NULL || axo->axo_cstate != AX_CSTATE_OPEN) {
+ axv->axv_include = 1;
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
+ agentx_varbind_nosuchobject(axv);
+ return;
+ }
+ bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
+ sizeof(axo_search.axo_oid));
+ axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
+getnext:
+ while (axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
+ axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
+ if (axo == NULL) {
+ agentx_varbind_endofmibview(axv);
+ return;
+ }
+ bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
+ sizeof(axo->axo_oid));
+ }
+ axv->axv_axo = axo;
+ axv->axv_indexlen = axo->axo_indexlen;
+ if (agentx_object_lock(axo) == -1) {
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
+ }
+
+ oid = &(axv->axv_vb.avb_oid);
+ if (axo->axo_indexlen == 0) {
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
+ if (oid->aoi_idlen != axo->axo_oid.aoi_idlen + 1 ||
+ oid->aoi_id[oid->aoi_idlen - 1] != 0) {
+ agentx_varbind_nosuchinstance(axv);
+ return;
+ }
+ } else {
+ if (oid->aoi_idlen == axo->axo_oid.aoi_idlen) {
+ oid->aoi_id[oid->aoi_idlen++] = 0;
+ axv->axv_include = 1;
+ } else {
+ axv->axv_axo = NULL;
+ agentx_object_unlock(axo);
+ axo = RB_NEXT(axc_objects, &(axc->axc_objects),
+ axo);
+ goto getnext;
+ }
+ }
+ }
+ j = axo->axo_oid.aoi_idlen;
+/*
+ * We can't trust what the client gives us, so sometimes we need to map it to
+ * index type.
+ * - AX_PDU_TYPE_GET: we always return AX_DATA_TYPE_NOSUCHINSTANCE
+ * - AX_PDU_TYPE_GETNEXT:
+ * - Missing OID digits to match indices will result in the indices to be NUL-
+ * initialized and the request type will be set to
+ * AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
+ * - An overflow can happen on AX_DATA_TYPE_OCTETSTRING and
+ * AX_DATA_TYPE_IPADDRESS. This results in request type being set to
+ * AGENTX_REQUEST_TYPE_GETNEXT and will set the index to its maximum
+ * value:
+ * - AX_DATA_TYPE_INTEGER: UINT32_MAX
+ * - AX_DATA_TYPE_OCTETSTRING: aos_slen = UINT32_MAX and
+ * aos_string = NULL
+ * - AX_DATA_TYPE_OID: aoi_idlen = UINT32_MAX and aoi_id[x] = UINT32_MAX
+ * - AX_DATA_TYPE_IPADDRESS: 255.255.255.255
+ */
+ for (dynamic = 0, i = 0; i < axo->axo_indexlen; i++) {
+ index = &(axv->axv_index[i]);
+ index->axv_axi = axo->axo_index[i];
+ data = &(index->axv_idata);
+ if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC)
+ dynamic = 1;
+ if (j >= axv->axv_vb.avb_oid.aoi_idlen && !overflow &&
+ axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC)
+ continue;
+ switch (axo->axo_index[i]->axi_vb.avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+/* Dynamic index: normal copy paste */
+ if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
+ data->avb_uint32 = overflow ?
+ UINT32_MAX : axv->axv_vb.avb_oid.aoi_id[j];
+ j++;
+ index->axv_idatacomplete = 1;
break;
}
+ axi = axo->axo_index[i];
+/* With a GET-request we need an exact match */
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
+ if (axi->axi_vb.avb_data.avb_uint32 !=
+ axv->axv_vb.avb_oid.aoi_id[j]) {
+ agentx_varbind_nosuchinstance(axv);
+ return;
+ }
+ index->axv_idatacomplete = 1;
+ j++;
+ break;
+ }
+/* A higher value automatically moves us to the next value */
+ if (overflow ||
+ axv->axv_vb.avb_oid.aoi_id[j] >
+ axi->axi_vb.avb_data.avb_uint32) {
+/* If we're !dynamic up until now the rest of the oid doesn't matter */
+ if (!dynamic) {
+ agentx_varbind_endofmibview(axv);
+ return;
+ }
+/*
+ * Else we just pick the max value and make sure we don't return
+ * AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
+ */
+ data->avb_uint32 = UINT32_MAX;
+ index->axv_idatacomplete = 1;
+ overflow = 1;
+ j++;
+ break;
+/*
+ * A lower value automatically moves to the set value and counts as a short oid
+ */
+ } else if (axv->axv_vb.avb_oid.aoi_id[j] <
+ axi->axi_vb.avb_data.avb_uint32) {
+ data->avb_uint32 =
+ axi->axi_vb.avb_data.avb_uint32;
+ j = axv->axv_vb.avb_oid.aoi_idlen;
+ break;
+ }
+/* Normal match, except we already matched overflow at higher value */
+ data->avb_uint32 = axv->axv_vb.avb_oid.aoi_id[j];
+ j++;
+ index->axv_idatacomplete = 1;
+ break;
+ case AX_DATA_TYPE_OCTETSTRING:
+ if (!agentx_object_implied(axo, index->axv_axi)) {
+ if (overflow || axv->axv_vb.avb_oid.aoi_id[j] >
+ AGENTX_OID_MAX_LEN -
+ axv->axv_vb.avb_oid.aoi_idlen) {
+ overflow = 1;
+ data->avb_ostring.aos_slen = UINT32_MAX;
+ index->axv_idatacomplete = 1;
+ continue;
+ }
+ data->avb_ostring.aos_slen =
+ axv->axv_vb.avb_oid.aoi_id[j++];
+ } else {
+ if (overflow) {
+ data->avb_ostring.aos_slen = UINT32_MAX;
+ index->axv_idatacomplete = 1;
+ continue;
+ }
+ data->avb_ostring.aos_slen =
+ axv->axv_vb.avb_oid.aoi_idlen - j;
+ }
+ data->avb_ostring.aos_string =
+ calloc(data->avb_ostring.aos_slen + 1, 1);
+ if (data->avb_ostring.aos_string == NULL) {
+ agentx_log_axg_warn(axg,
+ "Failed to bind string index");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
+ }
+ for (k = 0; k < data->avb_ostring.aos_slen; k++, j++) {
+ if (!overflow &&
+ j == axv->axv_vb.avb_oid.aoi_idlen)
+ break;
+
+ if (axv->axv_vb.avb_oid.aoi_id[j] > 255)
+ overflow = 1;
+
+ data->avb_ostring.aos_string[k] = overflow ?
+ 0xff : axv->axv_vb.avb_oid.aoi_id[j];
+ }
+ if (k == data->avb_ostring.aos_slen)
+ index->axv_idatacomplete = 1;
+ break;
+ case AX_DATA_TYPE_OID:
+ if (!agentx_object_implied(axo, index->axv_axi)) {
+ if (overflow || axv->axv_vb.avb_oid.aoi_id[j] >
+ AGENTX_OID_MAX_LEN -
+ axv->axv_vb.avb_oid.aoi_idlen) {
+ overflow = 1;
+ data->avb_oid.aoi_idlen = UINT32_MAX;
+ index->axv_idatacomplete = 1;
+ continue;
+ }
+ data->avb_oid.aoi_idlen =
+ axv->axv_vb.avb_oid.aoi_id[j++];
+ } else {
+ if (overflow) {
+ data->avb_oid.aoi_idlen = UINT32_MAX;
+ index->axv_idatacomplete = 1;
+ continue;
+ }
+ data->avb_oid.aoi_idlen =
+ axv->axv_vb.avb_oid.aoi_idlen - j;
+ }
+ for (k = 0; k < data->avb_oid.aoi_idlen; k++, j++) {
+ if (!overflow &&
+ j == axv->axv_vb.avb_oid.aoi_idlen) {
+ data->avb_oid.aoi_id[k] = 0;
+ continue;
+ }
+ data->avb_oid.aoi_id[k] = overflow ?
+ UINT32_MAX : axv->axv_vb.avb_oid.aoi_id[j];
+ }
+ if (j <= axv->axv_vb.avb_oid.aoi_idlen)
+ index->axv_idatacomplete = 1;
+ break;
+ case AX_DATA_TYPE_IPADDRESS:
+ ipaddress = calloc(1, sizeof(*ipaddress));
+ if (ipaddress == NULL) {
+ agentx_log_axg_warn(axg,
+ "Failed to bind ipaddress index");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
+ }
+ ipbytes = (unsigned char *)ipaddress;
+ for (k = 0; k < 4; k++, j++) {
+ if (!overflow &&
+ j == axv->axv_vb.avb_oid.aoi_idlen)
+ break;
+
+ if (axv->axv_vb.avb_oid.aoi_id[j] > 255)
+ overflow = 1;
+
+ ipbytes[k] = overflow ? 255 :
+ axv->axv_vb.avb_oid.aoi_id[j];
+ }
+ if (j <= axv->axv_vb.avb_oid.aoi_idlen)
+ index->axv_idatacomplete = 1;
+ data->avb_ostring.aos_slen = sizeof(*ipaddress);
+ data->avb_ostring.aos_string =
+ (unsigned char *)ipaddress;
+ break;
+ default:
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axg,
+ "%s: unexpected index type", __func__);
+#else
+ agentx_log_axg_warnx(axg,
+ "%s: unexpected index type", __func__);
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
+#endif
+ }
+ }
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
+ if ((axo->axo_indexlen > 0 &&
+ !axv->axv_index[axo->axo_indexlen - 1].axv_idatacomplete) ||
+ j != axv->axv_vb.avb_oid.aoi_idlen || overflow) {
+ agentx_varbind_nosuchinstance(axv);
+ return;
}
- } while (packetid == 0 || found);
- ax->ax_packetids[npackets] = packetid;
+ }
+
+ if (overflow || j > axv->axv_vb.avb_oid.aoi_idlen)
+ axv->axv_include = 0;
+
+/*
+ * AGENTX_REQUEST_TYPE_GETNEXT request can !dynamic objects can just move to
+ * the next object
+ */
+ if (agentx_varbind_request(axv) == AGENTX_REQUEST_TYPE_GETNEXT &&
+ !dynamic) {
+ agentx_varbind_endofmibview(axv);
+ return;
+ }
- return packetid;
+ axo->axo_get(axv);
}
-static int
-agentx_pdu_add_uint16(struct agentx *ax, uint16_t value)
+void
+agentx_varbind_integer(struct agentx_varbind *axv, uint32_t value)
{
- if (agentx_pdu_need(ax, sizeof(value)) == -1)
- return -1;
+ axv->axv_vb.avb_type = AX_DATA_TYPE_INTEGER;
+ axv->axv_vb.avb_data.avb_uint32 = value;
- if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE)
- value = htobe16(value);
- else
- value = htole16(value);
- memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
- ax->ax_wbtlen += sizeof(value);
- return 0;
+ agentx_varbind_finalize(axv);
}
-static int
-agentx_pdu_add_uint32(struct agentx *ax, uint32_t value)
+void
+agentx_varbind_string(struct agentx_varbind *axv, const char *value)
{
- if (agentx_pdu_need(ax, sizeof(value)) == -1)
- return -1;
+ agentx_varbind_nstring(axv, (const unsigned char *)value,
+ strlen(value));
+}
- if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE)
- value = htobe32(value);
- else
- value = htole32(value);
- memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
- ax->ax_wbtlen += sizeof(value);
- return 0;
+void
+agentx_varbind_nstring(struct agentx_varbind *axv,
+ const unsigned char *value, size_t slen)
+{
+ axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(slen);
+ if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
+ agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
+ }
+ axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
+ memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, slen);
+ axv->axv_vb.avb_data.avb_ostring.aos_slen = slen;
+
+ agentx_varbind_finalize(axv);
}
-static int
-agentx_pdu_add_uint64(struct agentx *ax, uint64_t value)
+void
+agentx_varbind_printf(struct agentx_varbind *axv, const char *fmt, ...)
{
- if (agentx_pdu_need(ax, sizeof(value)) == -1)
- return -1;
+ va_list ap;
+ int r;
+
+ axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
+ va_start(ap, fmt);
+ r = vasprintf((char **)&(axv->axv_vb.avb_data.avb_ostring.aos_string),
+ fmt, ap);
+ va_end(ap);
+ if (r == -1) {
+ axv->axv_vb.avb_data.avb_ostring.aos_string = NULL;
+ agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
+ }
+ axv->axv_vb.avb_data.avb_ostring.aos_slen = r;
- if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE)
- value = htobe64(value);
- else
- value = htole64(value);
- memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
- ax->ax_wbtlen += sizeof(value);
- return 0;
+ agentx_varbind_finalize(axv);
}
+void
+agentx_varbind_null(struct agentx_varbind *axv)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
-static int
-agentx_pdu_add_oid(struct agentx *ax, struct agentx_oid *oid, int include)
+ agentx_varbind_finalize(axv);
+}
+
+void
+agentx_varbind_oid(struct agentx_varbind *axv, const uint32_t oid[],
+ size_t oidlen)
{
- static struct agentx_oid nulloid = {0};
- uint8_t prefix = 0, n_subid, i = 0;
+ size_t i;
- n_subid = oid->aoi_idlen;
+ axv->axv_vb.avb_type = AX_DATA_TYPE_OID;
- if (oid == NULL)
- oid = &nulloid;
+ for (i = 0; i < oidlen; i++)
+ axv->axv_vb.avb_data.avb_oid.aoi_id[i] = oid[i];
+ axv->axv_vb.avb_data.avb_oid.aoi_idlen = oidlen;
- if (oid->aoi_idlen > 4 &&
- oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 &&
- oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 &&
- oid->aoi_id[4] <= UINT8_MAX) {
- prefix = oid->aoi_id[4];
- i = 5;
+ agentx_varbind_finalize(axv);
+}
+
+void
+agentx_varbind_object(struct agentx_varbind *axv,
+ struct agentx_object *axo)
+{
+ agentx_varbind_oid(axv, axo->axo_oid.aoi_id,
+ axo->axo_oid.aoi_idlen);
+}
+
+void
+agentx_varbind_index(struct agentx_varbind *axv,
+ struct agentx_index *axi)
+{
+ agentx_varbind_oid(axv, axi->axi_vb.avb_oid.aoi_id,
+ axi->axi_vb.avb_oid.aoi_idlen);
+}
+
+
+void
+agentx_varbind_ipaddress(struct agentx_varbind *axv,
+ const struct in_addr *value)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_IPADDRESS;
+ axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(4);
+ if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
+ agentx_log_axg_warn(axv->axv_axg, "Couldn't bind ipaddress");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
}
+ memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, 4);
+ axv->axv_vb.avb_data.avb_ostring.aos_slen = 4;
- if (agentx_pdu_need(ax, 4) == -1)
- return -1;
- ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i;
- ax->ax_wbuf[ax->ax_wbtlen++] = prefix;
- ax->ax_wbuf[ax->ax_wbtlen++] = !!include;
- ax->ax_wbuf[ax->ax_wbtlen++] = 0;
+ agentx_varbind_finalize(axv);
+}
- for (; i < n_subid; i++) {
- if (agentx_pdu_add_uint32(ax, oid->aoi_id[i]) == -1)
- return -1;
+void
+agentx_varbind_counter32(struct agentx_varbind *axv, uint32_t value)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER32;
+ axv->axv_vb.avb_data.avb_uint32 = value;
+
+ agentx_varbind_finalize(axv);
+}
+
+void
+agentx_varbind_gauge32(struct agentx_varbind *axv, uint32_t value)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_GAUGE32;
+ axv->axv_vb.avb_data.avb_uint32 = value;
+
+ agentx_varbind_finalize(axv);
+}
+
+void
+agentx_varbind_timeticks(struct agentx_varbind *axv, uint32_t value)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_TIMETICKS;
+ axv->axv_vb.avb_data.avb_uint32 = value;
+
+ agentx_varbind_finalize(axv);
+}
+
+void
+agentx_varbind_opaque(struct agentx_varbind *axv, const char *string,
+ size_t strlen)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_OPAQUE;
+ axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(strlen);
+ if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
+ agentx_log_axg_warn(axv->axv_axg, "Couldn't bind opaque");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 1);
+ return;
}
+ memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, string, strlen);
+ axv->axv_vb.avb_data.avb_ostring.aos_slen = strlen;
- return 0;
+ agentx_varbind_finalize(axv);
}
-static int
-agentx_pdu_add_str(struct agentx *ax, struct agentx_ostring *str)
+void
+agentx_varbind_counter64(struct agentx_varbind *axv, uint64_t value)
{
- size_t length, zeroes;
+ axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER64;
+ axv->axv_vb.avb_data.avb_uint64 = value;
- if (agentx_pdu_add_uint32(ax, str->aos_slen) == -1)
- return -1;
+ agentx_varbind_finalize(axv);
+}
- if ((zeroes = (4 - (str->aos_slen % 4))) == 4)
- zeroes = 0;
- length = str->aos_slen + zeroes;
- if (agentx_pdu_need(ax, length) == -1)
- return -1;
+void
+agentx_varbind_notfound(struct agentx_varbind *axv)
+{
+ if (axv->axv_indexlen == 0) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "%s invalid call",
+ __func__);
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "%s invalid call",
+ __func__);
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 1);
+#endif
+ } else if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
+ agentx_varbind_nosuchinstance(axv);
+ else
+ agentx_varbind_endofmibview(axv);
+}
- memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen);
- ax->ax_wbtlen += str->aos_slen;
- memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes);
- ax->ax_wbtlen += zeroes;
- return 0;
+void
+agentx_varbind_error(struct agentx_varbind *axv)
+{
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 1);
}
-static int
-agentx_pdu_add_varbindlist(struct agentx *ax,
- struct agentx_varbind *vblist, size_t nvb)
+static void
+agentx_varbind_error_type(struct agentx_varbind *axv,
+ enum ax_pdu_error error, int done)
{
- size_t i;
- uint16_t temp;
+ if (axv->axv_error == AX_PDU_ERROR_NOERROR) {
+ axv->axv_error = error;
+ }
- for (i = 0; i < nvb; i++) {
- temp = (uint16_t) vblist[i].avb_type;
- if (agentx_pdu_add_uint16(ax, temp) == -1 ||
- agentx_pdu_need(ax, 2))
- return -1;
- memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2);
- ax->ax_wbtlen += 2;
- if (agentx_pdu_add_oid(ax, &(vblist[i].avb_oid), 0) == -1)
- return -1;
- switch (vblist[i].avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
- case AGENTX_DATA_TYPE_COUNTER32:
- case AGENTX_DATA_TYPE_GAUGE32:
- case AGENTX_DATA_TYPE_TIMETICKS:
- if (agentx_pdu_add_uint32(ax,
- vblist[i].avb_data.avb_uint32) == -1)
- return -1;
- break;
- case AGENTX_DATA_TYPE_COUNTER64:
- if (agentx_pdu_add_uint64(ax,
- vblist[i].avb_data.avb_uint64) == -1)
- return -1;
+ if (done) {
+ axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
+
+ agentx_varbind_finalize(axv);
+ }
+}
+
+static void
+agentx_varbind_finalize(struct agentx_varbind *axv)
+{
+ struct agentx_get *axg = axv->axv_axg;
+ struct ax_oid oid;
+ union ax_data *data;
+ size_t i, j;
+ int cmp;
+
+ if (axv->axv_error != AX_PDU_ERROR_NOERROR) {
+ bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
+ sizeof(axv->axv_start));
+ goto done;
+ }
+ bcopy(&(axv->axv_axo->axo_oid), &oid, sizeof(oid));
+ if (axv->axv_indexlen == 0)
+ ax_oid_add(&oid, 0);
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ data = &(axv->axv_index[i].axv_idata);
+ switch (axv->axv_index[i].axv_axi->axi_vb.avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+ if (ax_oid_add(&oid, data->avb_uint32) == -1)
+ goto fail;
break;
- case AGENTX_DATA_TYPE_OCTETSTRING:
- case AGENTX_DATA_TYPE_IPADDRESS:
- case AGENTX_DATA_TYPE_OPAQUE:
- if (agentx_pdu_add_str(ax,
- &(vblist[i].avb_data.avb_ostring)) == -1)
- return -1;
+ case AX_DATA_TYPE_OCTETSTRING:
+ if (!agentx_object_implied(axv->axv_axo,
+ axv->axv_index[i].axv_axi)) {
+ if (ax_oid_add(&oid,
+ data->avb_ostring.aos_slen) == -1)
+ goto fail;
+ }
+ for (j = 0; j < data->avb_ostring.aos_slen; j++) {
+ if (ax_oid_add(&oid,
+ (uint8_t)data->avb_ostring.aos_string[j]) ==
+ -1)
+ goto fail;
+ }
break;
- case AGENTX_DATA_TYPE_OID:
- if (agentx_pdu_add_oid(ax,
- &(vblist[i].avb_data.avb_oid), 1) == -1)
- return -1;
+ case AX_DATA_TYPE_OID:
+ if (!agentx_object_implied(axv->axv_axo,
+ axv->axv_index[i].axv_axi)) {
+ if (ax_oid_add(&oid,
+ data->avb_oid.aoi_idlen) == -1)
+ goto fail;
+ }
+ for (j = 0; j < data->avb_oid.aoi_idlen; j++) {
+ if (ax_oid_add(&oid,
+ data->avb_oid.aoi_id[j]) == -1)
+ goto fail;
+ }
break;
- case AGENTX_DATA_TYPE_NULL:
- case AGENTX_DATA_TYPE_NOSUCHOBJECT:
- case AGENTX_DATA_TYPE_NOSUCHINSTANCE:
- case AGENTX_DATA_TYPE_ENDOFMIBVIEW:
+ case AX_DATA_TYPE_IPADDRESS:
+ for (j = 0; j < 4; j++) {
+ if (ax_oid_add(&oid,
+ data->avb_ostring.aos_string == NULL ? 0 :
+ (uint8_t)data->avb_ostring.aos_string[j]) ==
+ -1)
+ goto fail;
+ }
break;
default:
- errno = EINVAL;
- return -1;
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axg,
+ "%s: unsupported index type", __func__);
+#else
+ bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
+ sizeof(axv->axv_start));
+ axv->axv_error = AX_PDU_ERROR_PROCESSINGERROR;
+ agentx_object_unlock(axv->axv_axo);
+ agentx_get_finalize(axv->axv_axg);
+ return;
+#endif
}
}
+ cmp = ax_oid_cmp(&(axv->axv_vb.avb_oid), &oid);
+ if ((agentx_varbind_request(axv) == AGENTX_REQUEST_TYPE_GETNEXT &&
+ cmp >= 0) || cmp > 0) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axg, "indices not incremented");
+#else
+ agentx_log_axg_warnx(axg, "indices not incremented");
+ bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
+ sizeof(axv->axv_start));
+ axv->axv_error = AX_PDU_ERROR_GENERR;
+#endif
+ } else
+ bcopy(&oid, &(axv->axv_vb.avb_oid), sizeof(oid));
+done:
+ agentx_object_unlock(axv->axv_axo);
+ agentx_get_finalize(axv->axv_axg);
+ return;
+
+fail:
+ agentx_log_axg_warnx(axg, "oid too large");
+ bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
+ sizeof(axv->axv_start));
+ axv->axv_error = AX_PDU_ERROR_GENERR;
+ agentx_object_unlock(axv->axv_axo);
+ agentx_get_finalize(axv->axv_axg);
+}
+
+static void
+agentx_varbind_nosuchobject(struct agentx_varbind *axv)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHOBJECT;
+
+ if (axv->axv_axo != NULL)
+ agentx_object_unlock(axv->axv_axo);
+ agentx_get_finalize(axv->axv_axg);
+}
+
+static void
+agentx_varbind_nosuchinstance(struct agentx_varbind *axv)
+{
+ axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHINSTANCE;
+
+ if (axv->axv_axo != NULL)
+ agentx_object_unlock(axv->axv_axo);
+ agentx_get_finalize(axv->axv_axg);
+}
+
+static void
+agentx_varbind_endofmibview(struct agentx_varbind *axv)
+{
+ struct agentx_object *axo;
+ struct ax_varbind *vb;
+ struct agentx_varbind_index *index;
+ size_t i;
+
+#ifdef AX_DEBUG
+ if (axv->axv_axg->axg_type != AX_PDU_TYPE_GETNEXT &&
+ axv->axv_axg->axg_type != AX_PDU_TYPE_GETBULK)
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "%s: invalid request type", __func__);
+#endif
+
+ if (axv->axv_axo != NULL &&
+ (axo = RB_NEXT(axc_objects, &(axc->axc_objects),
+ axv->axv_axo)) != NULL &&
+ ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) < 0) {
+ bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
+ sizeof(axo->axo_oid));
+ axv->axv_include = 1;
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ index = &(axv->axv_index[i]);
+ vb = &(index->axv_axi->axi_vb);
+ if (vb->avb_type == AX_DATA_TYPE_OCTETSTRING ||
+ vb->avb_type == AX_DATA_TYPE_IPADDRESS)
+ free(index->axv_idata.avb_ostring.aos_string);
+ }
+ bzero(&(axv->axv_index), sizeof(axv->axv_index));
+ agentx_object_unlock(axv->axv_axo);
+ agentx_varbind_start(axv);
+ return;
+ }
+
+ axv->axv_vb.avb_type = AX_DATA_TYPE_ENDOFMIBVIEW;
+
+ if (axv->axv_axo != NULL)
+ agentx_object_unlock(axv->axv_axo);
+ agentx_get_finalize(axv->axv_axg);
+}
+
+enum agentx_request_type
+agentx_varbind_request(struct agentx_varbind *axv)
+{
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
+ return AGENTX_REQUEST_TYPE_GET;
+ if (axv->axv_include ||
+ (axv->axv_indexlen > 0 &&
+ !axv->axv_index[axv->axv_indexlen - 1].axv_idatacomplete))
+ return AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE;
+ return AGENTX_REQUEST_TYPE_GETNEXT;
+}
+
+struct agentx_object *
+agentx_varbind_get_object(struct agentx_varbind *axv)
+{
+ return axv->axv_axo;
+}
+
+uint32_t
+agentx_varbind_get_index_integer(struct agentx_varbind *axv,
+ struct agentx_index *axi)
+{
+ size_t i;
+
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return 0;
+#endif
+ }
+
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi)
+ return axv->axv_index[i].axv_idata.avb_uint32;
+ }
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
return 0;
+#endif
}
-static uint16_t
-agentx_pdutoh16(struct agentx_pdu_header *header, uint8_t *buf)
+const unsigned char *
+agentx_varbind_get_index_string(struct agentx_varbind *axv,
+ struct agentx_index *axi, size_t *slen, int *implied)
{
- uint16_t value;
+ struct agentx_varbind_index *index;
+ size_t i;
+
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ *slen = 0;
+ *implied = 0;
+ return NULL;
+#endif
+ }
- memcpy(&value, buf, sizeof(value));
- if (header->aph_flags & AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER)
- return be16toh(value);
- return le16toh(value);
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ index = &(axv->axv_index[i]);
+ *slen = index->axv_idata.avb_ostring.aos_slen;
+ *implied = agentx_object_implied(axv->axv_axo, axi);
+ return index->axv_idata.avb_ostring.aos_string;
+ }
+ }
+
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ *slen = 0;
+ *implied = 0;
+ return NULL;
+#endif
}
-static uint32_t
-agentx_pdutoh32(struct agentx_pdu_header *header, uint8_t *buf)
+const uint32_t *
+agentx_varbind_get_index_oid(struct agentx_varbind *axv,
+ struct agentx_index *axi, size_t *oidlen, int *implied)
{
- uint32_t value;
+ struct agentx_varbind_index *index;
+ size_t i;
- memcpy(&value, buf, sizeof(value));
- if (header->aph_flags & AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER)
- return be32toh(value);
- return le32toh(value);
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ *oidlen = 0;
+ *implied = 0;
+ return NULL;
+#endif
+ }
+
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ index = &(axv->axv_index[i]);
+ *oidlen = index->axv_idata.avb_oid.aoi_idlen;
+ *implied = agentx_object_implied(axv->axv_axo, axi);
+ return index->axv_idata.avb_oid.aoi_id;
+ }
+ }
+
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ *oidlen = 0;
+ *implied = 0;
+ return NULL;
+#endif
}
-static uint64_t
-agentx_pdutoh64(struct agentx_pdu_header *header, uint8_t *buf)
+const struct in_addr *
+agentx_varbind_get_index_ipaddress(struct agentx_varbind *axv,
+ struct agentx_index *axi)
{
- uint64_t value;
+ static struct in_addr nuladdr = {0};
+ struct agentx_varbind_index *index;
+ size_t i;
- memcpy(&value, buf, sizeof(value));
- if (header->aph_flags & AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER)
- return be64toh(value);
- return le64toh(value);
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return NULL;
+#endif
+ }
+
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ index = &(axv->axv_index[i]);
+ if (index->axv_idata.avb_ostring.aos_string == NULL)
+ return &nuladdr;
+ return (struct in_addr *)
+ index->axv_idata.avb_ostring.aos_string;
+ }
+ }
+
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return NULL;
+#endif
}
-static ssize_t
-agentx_pdutooid(struct agentx_pdu_header *header, struct agentx_oid *oid,
- uint8_t *buf, size_t rawlen)
+void
+agentx_varbind_set_index_integer(struct agentx_varbind *axv,
+ struct agentx_index *axi, uint32_t value)
{
- size_t i = 0;
- ssize_t nread;
-
- if (rawlen < 4)
- goto fail;
- rawlen -= 4;
- nread = 4;
- oid->aoi_idlen = *buf++;
- if (rawlen < (oid->aoi_idlen * 4))
- goto fail;
- nread += oid->aoi_idlen * 4;
- if (*buf != 0) {
- oid->aoi_id[0] = 1;
- oid->aoi_id[1] = 3;
- oid->aoi_id[2] = 6;
- oid->aoi_id[3] = 1;
- oid->aoi_id[4] = *buf;
- oid->aoi_idlen += 5;
- i = 5;
- }
- buf++;
- oid->aoi_include = *buf;
- for (buf += 2; i < oid->aoi_idlen; i++, buf += 4)
- oid->aoi_id[i] = agentx_pdutoh32(header, buf);
-
- return nread;
+ size_t i;
-fail:
- errno = EPROTO;
- return -1;
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
+ axv->axv_index[i].axv_idata.avb_uint32 != value) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "can't change index on GET");
+#else
+ agentx_log_axg_warnx(axv->axv_axg,
+ "can't change index on GET");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+ axv->axv_index[i].axv_idata.avb_uint32 = value;
+ return;
+ }
+ }
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+#endif
}
-static ssize_t
-agentx_pdutoostring(struct agentx_pdu_header *header,
- struct agentx_ostring *ostring, uint8_t *buf, size_t rawlen)
+void
+agentx_varbind_set_index_string(struct agentx_varbind *axv,
+ struct agentx_index *axi, const char *value)
{
- ssize_t nread;
+ agentx_varbind_set_index_nstring(axv, axi,
+ (const unsigned char *)value, strlen(value));
+}
- if (rawlen < 4)
- goto fail;
+void
+agentx_varbind_set_index_nstring(struct agentx_varbind *axv,
+ struct agentx_index *axi, const unsigned char *value, size_t slen)
+{
+ struct ax_ostring *curvalue;
+ unsigned char *nstring;
+ size_t i;
- ostring->aos_slen = agentx_pdutoh32(header, buf);
- rawlen -= 4;
- buf += 4;
- if (ostring->aos_slen > rawlen)
- goto fail;
- if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL)
- return -1;
- memcpy(ostring->aos_string, buf, ostring->aos_slen);
- ostring->aos_string[ostring->aos_slen] = '\0';
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
- nread = 4 + ostring->aos_slen;
- if (ostring->aos_slen % 4 != 0)
- nread += 4 - (ostring->aos_slen % 4);
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ if (axi->axi_vb.avb_data.avb_ostring.aos_slen != 0 &&
+ axi->axi_vb.avb_data.avb_ostring.aos_slen != slen) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "invalid string length on explicit length "
+ "string");
+#else
+ agentx_log_axg_warnx(axv->axv_axg,
+ "invalid string length on explicit length "
+ "string");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+ curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
+ (curvalue->aos_slen != slen ||
+ memcmp(curvalue->aos_string, value, slen) != 0)) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "can't change index on GET");
+#else
+ agentx_log_axg_warnx(axv->axv_axg,
+ "can't change index on GET");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+ if ((nstring = recallocarray(curvalue->aos_string,
+ curvalue->aos_slen + 1, slen + 1, 1)) == NULL) {
+ agentx_log_axg_warn(axv->axv_axg,
+ "Failed to bind string index");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 0);
+ return;
+ }
+ curvalue->aos_string = nstring;
+ memcpy(nstring, value, slen);
+ curvalue->aos_slen = slen;
+ return;
+ }
+ }
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+#endif
+}
- return nread;
+void
+agentx_varbind_set_index_oid(struct agentx_varbind *axv,
+ struct agentx_index *axi, const uint32_t *value, size_t oidlen)
+{
+ struct ax_oid *curvalue, oid;
+ size_t i;
-fail:
- errno = EPROTO;
- return -1;
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ if (axi->axi_vb.avb_data.avb_oid.aoi_idlen != 0 &&
+ axi->axi_vb.avb_data.avb_oid.aoi_idlen != oidlen) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "invalid oid length on explicit length "
+ "oid");
+#else
+ agentx_log_axg_warnx(axv->axv_axg,
+ "invalid oid length on explicit length "
+ "oid");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+ curvalue = &(axv->axv_index[i].axv_idata.avb_oid);
+ for (i = 0; i < oidlen; i++)
+ oid.aoi_id[i] = value[i];
+ oid.aoi_idlen = oidlen;
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
+ ax_oid_cmp(&oid, curvalue) != 0) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "can't change index on GET");
+#else
+ agentx_log_axg_warnx(axv->axv_axg,
+ "can't change index on GET");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+ for (i = 0; i < oidlen; i++)
+ curvalue->aoi_id[i] = value[i];
+ curvalue->aoi_idlen = oidlen;
+ return;
+ }
+ }
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+#endif
+}
+
+void
+agentx_varbind_set_index_object(struct agentx_varbind *axv,
+ struct agentx_index *axi, struct agentx_object *axo)
+{
+ agentx_varbind_set_index_oid(axv, axi, axo->axo_oid.aoi_id,
+ axo->axo_oid.aoi_idlen);
}
-static ssize_t
-agentx_pdutovarbind(struct agentx_pdu_header *header,
- struct agentx_varbind *varbind, uint8_t *buf, size_t rawlen)
+void
+agentx_varbind_set_index_ipaddress(struct agentx_varbind *axv,
+ struct agentx_index *axi, const struct in_addr *addr)
{
- ssize_t nread, rread = 4;
+ struct ax_ostring *curvalue;
+ size_t i;
- if (rawlen == 0)
- return 0;
+ if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
- if (rawlen < 8)
- goto fail;
- varbind->avb_type = agentx_pdutoh16(header, buf);
+ for (i = 0; i < axv->axv_indexlen; i++) {
+ if (axv->axv_index[i].axv_axi == axi) {
+ curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
+ if (curvalue->aos_string == NULL)
+ curvalue->aos_string = calloc(1, sizeof(*addr));
+ if (curvalue->aos_string == NULL) {
+ agentx_log_axg_warn(axv->axv_axg,
+ "Failed to bind ipaddress index");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_PROCESSINGERROR, 0);
+ return;
+ }
+ if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
+ memcmp(addr, curvalue->aos_string,
+ sizeof(*addr)) != 0) {
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg,
+ "can't change index on GET");
+#else
+ agentx_log_axg_warnx(axv->axv_axg,
+ "can't change index on GET");
+ agentx_varbind_error_type(axv,
+ AX_PDU_ERROR_GENERR, 0);
+ return;
+#endif
+ }
+ bcopy(addr, curvalue->aos_string, sizeof(*addr));
+ return;
+ }
+ }
+#ifdef AX_DEBUG
+ agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
+#else
+ agentx_log_axg_warnx(axv->axv_axg, "invalid index");
+ agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
+#endif
+}
+
+static int
+agentx_request(struct agentx *ax, uint32_t packetid,
+ int (*cb)(struct ax_pdu *, void *), void *cookie)
+{
+ struct agentx_request *axr;
- buf += 4;
- rawlen -= 4;
- nread = agentx_pdutooid(header, &(varbind->avb_oid), buf, rawlen);
- if (nread == -1)
+#ifdef AX_DEBUG
+ if (ax->ax_ax->ax_wblen == 0)
+ agentx_log_ax_fatalx(ax, "%s: no data to be written",
+ __func__);
+#endif
+
+ if ((axr = calloc(1, sizeof(*axr))) == NULL) {
+ agentx_log_ax_warn(ax, "couldn't create request context");
+ agentx_reset(ax);
return -1;
- rread += nread;
- buf += nread;
- rawlen -= nread;
-
- switch(varbind->avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
- case AGENTX_DATA_TYPE_COUNTER32:
- case AGENTX_DATA_TYPE_GAUGE32:
- case AGENTX_DATA_TYPE_TIMETICKS:
- if (rawlen < 4)
- goto fail;
- varbind->avb_data.avb_uint32 = agentx_pdutoh32(header, buf);
- return rread + 4;
- case AGENTX_DATA_TYPE_COUNTER64:
- if (rawlen < 8)
- goto fail;
- varbind->avb_data.avb_uint64 = agentx_pdutoh64(header, buf);
- return rread + 8;
- case AGENTX_DATA_TYPE_OCTETSTRING:
- case AGENTX_DATA_TYPE_IPADDRESS:
- case AGENTX_DATA_TYPE_OPAQUE:
- nread = agentx_pdutoostring(header,
- &(varbind->avb_data.avb_ostring), buf, rawlen);
- if (nread == -1)
- return -1;
- return nread + rread;
- case AGENTX_DATA_TYPE_OID:
- nread = agentx_pdutooid(header, &(varbind->avb_data.avb_oid),
- buf, rawlen);
- if (nread == -1)
+ }
+
+ axr->axr_packetid = packetid;
+ axr->axr_cb = cb;
+ axr->axr_cookie = cookie;
+ if (RB_INSERT(ax_requests, &(ax->ax_requests), axr) != NULL) {
+#ifdef AX_DEBUG
+ agentx_log_ax_fatalx(ax, "%s: duplicate packetid", __func__);
+#else
+ agentx_log_ax_warnx(ax, "%s: duplicate packetid", __func__);
+ free(axr);
+ agentx_reset(ax);
+ return -1;
+#endif
+ }
+
+ agentx_wantwrite(ax, ax->ax_fd);
+ return 0;
+}
+
+static int
+agentx_request_cmp(struct agentx_request *r1,
+ struct agentx_request *r2)
+{
+ return r1->axr_packetid < r2->axr_packetid ? -1 :
+ r1->axr_packetid > r2->axr_packetid;
+}
+
+static int
+agentx_strcat(char **dst, const char *src)
+{
+ char *tmp;
+ size_t dstlen = 0, buflen = 0, srclen, nbuflen;
+
+ if (*dst != NULL) {
+ dstlen = strlen(*dst);
+ buflen = ((dstlen / 512) + 1) * 512;
+ }
+
+ srclen = strlen(src);
+ if (*dst == NULL || dstlen + srclen > buflen) {
+ nbuflen = (((dstlen + srclen) / 512) + 1) * 512;
+ tmp = recallocarray(*dst, buflen, nbuflen, sizeof(*tmp));
+ if (tmp == NULL)
return -1;
- return nread + rread;
- case AGENTX_DATA_TYPE_NULL:
- case AGENTX_DATA_TYPE_NOSUCHOBJECT:
- case AGENTX_DATA_TYPE_NOSUCHINSTANCE:
- case AGENTX_DATA_TYPE_ENDOFMIBVIEW:
- return rread;
+ *dst = tmp;
+ buflen = nbuflen;
}
-fail:
- errno = EPROTO;
- return -1;
+ (void)strlcat(*dst, src, buflen);
+ return 0;
}
+
+void
+agentx_read(struct agentx *ax)
+{
+ struct agentx_session *axs;
+ struct agentx_context *axc;
+ struct agentx_request axr_search, *axr;
+ struct ax_pdu *pdu;
+ int error;
+
+ if ((pdu = ax_recv(ax->ax_ax)) == NULL) {
+ if (errno == EAGAIN)
+ return;
+ agentx_log_ax_warn(ax, "lost connection");
+ agentx_reset(ax);
+ return;
+ }
+
+ TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
+ if (axs->axs_id == pdu->ap_header.aph_sessionid)
+ break;
+ if (axs->axs_cstate == AX_CSTATE_WAITOPEN &&
+ axs->axs_packetid == pdu->ap_header.aph_packetid)
+ break;
+ }
+ if (axs == NULL) {
+ agentx_log_ax_warnx(ax, "received unexpected session: %d",
+ pdu->ap_header.aph_sessionid);
+ ax_pdu_free(pdu);
+ agentx_reset(ax);
+ return;
+ }
+ TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts) {
+ if ((pdu->ap_header.aph_flags &
+ AX_PDU_FLAG_NON_DEFAULT_CONTEXT) == 0 &&
+ axc->axc_name_default == 1)
+ break;
+ if (pdu->ap_header.aph_flags &
+ AX_PDU_FLAG_NON_DEFAULT_CONTEXT &&
+ axc->axc_name_default == 0 &&
+ pdu->ap_context.aos_slen == axc->axc_name.aos_slen &&
+ memcmp(pdu->ap_context.aos_string,
+ axc->axc_name.aos_string, axc->axc_name.aos_slen) == 0)
+ break;
+ }
+ if (pdu->ap_header.aph_type != AX_PDU_TYPE_RESPONSE) {
+ if (axc == NULL) {
+ agentx_log_ax_warnx(ax, "%s: invalid context",
+ pdu->ap_context.aos_string);
+ ax_pdu_free(pdu);
+ agentx_reset(ax);
+ return;
+ }
+ }
+
+ switch (pdu->ap_header.aph_type) {
+ case AX_PDU_TYPE_GET:
+ case AX_PDU_TYPE_GETNEXT:
+ case AX_PDU_TYPE_GETBULK:
+ agentx_get_start(axc, pdu);
+ break;
+ /* Add stubs for set functions */
+ case AX_PDU_TYPE_TESTSET:
+ case AX_PDU_TYPE_COMMITSET:
+ case AX_PDU_TYPE_UNDOSET:
+ if (pdu->ap_header.aph_type == AX_PDU_TYPE_TESTSET)
+ error = AX_PDU_ERROR_NOTWRITABLE;
+ else if (pdu->ap_header.aph_type == AX_PDU_TYPE_COMMITSET)
+ error = AX_PDU_ERROR_COMMITFAILED;
+ else
+ error = AX_PDU_ERROR_UNDOFAILED;
+
+ agentx_log_axc_debug(axc, "unsupported call: %s",
+ ax_pdutype2string(pdu->ap_header.aph_type));
+ if (ax_response(ax->ax_ax, axs->axs_id,
+ pdu->ap_header.aph_transactionid,
+ pdu->ap_header.aph_packetid,
+ axc == NULL ? NULL : AGENTX_CONTEXT_CTX(axc),
+ 0, error, 1, NULL, 0) == -1)
+ agentx_log_axc_warn(axc,
+ "transaction: %u packetid: %u: failed to send "
+ "reply", pdu->ap_header.aph_transactionid,
+ pdu->ap_header.aph_packetid);
+ if (ax->ax_ax->ax_wblen > 0)
+ agentx_wantwrite(ax, ax->ax_fd);
+ break;
+ case AX_PDU_TYPE_CLEANUPSET:
+ agentx_log_ax_debug(ax, "unsupported call: %s",
+ ax_pdutype2string(pdu->ap_header.aph_type));
+ break;
+ case AX_PDU_TYPE_RESPONSE:
+ axr_search.axr_packetid = pdu->ap_header.aph_packetid;
+ axr = RB_FIND(ax_requests, &(ax->ax_requests), &axr_search);
+ if (axr == NULL) {
+ if (axc == NULL)
+ agentx_log_ax_warnx(ax, "received "
+ "response on non-request");
+ else
+ agentx_log_axc_warnx(axc, "received "
+ "response on non-request");
+ break;
+ }
+ if (axc != NULL && pdu->ap_payload.ap_response.ap_error == 0) {
+ axc->axc_sysuptime =
+ pdu->ap_payload.ap_response.ap_uptime;
+ (void) clock_gettime(CLOCK_MONOTONIC,
+ &(axc->axc_sysuptimespec));
+ }
+ RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
+ (void) axr->axr_cb(pdu, axr->axr_cookie);
+ free(axr);
+ break;
+ default:
+ if (axc == NULL)
+ agentx_log_ax_warnx(ax, "unsupported call: %s",
+ ax_pdutype2string(pdu->ap_header.aph_type));
+ else
+ agentx_log_axc_warnx(axc, "unsupported call: %s",
+ ax_pdutype2string(pdu->ap_header.aph_type));
+ agentx_reset(ax);
+ break;
+ }
+ ax_pdu_free(pdu);
+}
+
+void
+agentx_write(struct agentx *ax)
+{
+ ssize_t send;
+
+ if ((send = ax_send(ax->ax_ax)) == -1) {
+ if (errno == EAGAIN) {
+ agentx_wantwrite(ax, ax->ax_fd);
+ return;
+ }
+ agentx_log_ax_warn(ax, "lost connection");
+ agentx_reset(ax);
+ return;
+ }
+ if (send > 0)
+ agentx_wantwrite(ax, ax->ax_fd);
+}
+
+RB_GENERATE_STATIC(ax_requests, agentx_request, axr_ax_requests,
+ agentx_request_cmp)
+RB_GENERATE_STATIC(axc_objects, agentx_object, axo_axc_objects,
+ agentx_object_cmp)
diff --git a/lib/libagentx/agentx.h b/lib/libagentx/agentx.h
index 2300c79117a..fb634fcd803 100644
--- a/lib/libagentx/agentx.h
+++ b/lib/libagentx/agentx.h
@@ -14,219 +14,134 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdint.h>
-
-#define AGENTX_PDU_FLAG_INSTANCE_REGISTRATION (1 << 0)
-#define AGENTX_PDU_FLAG_NEW_INDEX (1 << 1)
-#define AGENTX_PDU_FLAG_ANY_INDEX (1 << 2)
-#define AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT (1 << 3)
-#define AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER (1 << 4)
-
-#define AGENTX_PRIORITY_DEFAULT 127
-
-enum agentx_byte_order {
- AGENTX_BYTE_ORDER_BE,
- AGENTX_BYTE_ORDER_LE
-};
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define AGENTX_BYTE_ORDER_NATIVE AGENTX_BYTE_ORDER_BE
-#else
-#define AGENTX_BYTE_ORDER_NATIVE AGENTX_BYTE_ORDER_LE
-#endif
-
-enum agentx_pdu_type {
- AGENTX_PDU_TYPE_OPEN = 1,
- AGENTX_PDU_TYPE_CLOSE = 2,
- AGENTX_PDU_TYPE_REGISTER = 3,
- AGENTX_PDU_TYPE_UNREGISTER = 4,
- AGENTX_PDU_TYPE_GET = 5,
- AGENTX_PDU_TYPE_GETNEXT = 6,
- AGENTX_PDU_TYPE_GETBULK = 7,
- AGENTX_PDU_TYPE_TESTSET = 8,
- AGENTX_PDU_TYPE_COMMITSET = 9,
- AGENTX_PDU_TYPE_UNDOSET = 10,
- AGENTX_PDU_TYPE_CLEANUPSET = 11,
- AGENTX_PDU_TYPE_NOTIFY = 12,
- AGENTX_PDU_TYPE_PING = 13,
- AGENTX_PDU_TYPE_INDEXALLOCATE = 14,
- AGENTX_PDU_TYPE_INDEXDEALLOCATE = 15,
- AGENTX_PDU_TYPE_ADDAGENTCAPS = 16,
- AGENTX_PDU_TYPE_REMOVEAGENTCAPS = 17,
- AGENTX_PDU_TYPE_RESPONSE = 18
-};
+#include <netinet/in.h>
-enum agentx_pdu_error {
- AGENTX_PDU_ERROR_NOERROR = 0,
- AGENTX_PDU_ERROR_GENERR = 5,
- AGENTX_PDU_ERROR_NOACCESS = 6,
- AGENTX_PDU_ERROR_WRONGTYPE = 7,
- AGENTX_PDU_ERROR_WRONGLENGTH = 8,
- AGENTX_PDU_ERROR_WRONGENCODING = 9,
- AGENTX_PDU_ERROR_WRONGVALUE = 10,
- AGENTX_PDU_ERROR_NOCREATION = 11,
- AGENTX_PDU_ERROR_INCONSISTENTVALUE = 12,
- AGENTX_PDU_ERROR_RESOURCEUNAVAILABLE = 13,
- AGENTX_PDU_ERROR_COMMITFAILED = 14,
- AGENTX_PDU_ERROR_UNDOFAILED = 15,
- AGENTX_PDU_ERROR_NOTWRITABLE = 17,
- AGENTX_PDU_ERROR_INCONSISTENTNAME = 18,
- AGENTX_PDU_ERROR_OPENFAILED = 256,
- AGENTX_PDU_ERROR_NOTOPEN = 257,
- AGENTX_PDU_ERROR_INDEXWRONGTYPE = 258,
- AGENTX_PDU_ERROR_INDEXALREADYALLOCATED = 259,
- AGENTX_PDU_ERROR_INDEXNONEAVAILABLE = 260,
- AGENTX_PDU_ERROR_INDEXNOTALLOCATED = 261,
- AGENTX_PDU_ERROR_UNSUPPORTEDCONETXT = 262,
- AGENTX_PDU_ERROR_DUPLICATEREGISTRATION = 263,
- AGENTX_PDU_ERROR_UNKNOWNREGISTRATION = 264,
- AGENTX_PDU_ERROR_UNKNOWNAGENTCAPS = 265,
- AGENTX_PDU_ERROR_PARSEERROR = 266,
- AGENTX_PDU_ERROR_REQUESTDENIED = 267,
- AGENTX_PDU_ERROR_PROCESSINGERROR = 268
-};
-
-enum agentx_data_type {
- AGENTX_DATA_TYPE_INTEGER = 2,
- AGENTX_DATA_TYPE_OCTETSTRING = 4,
- AGENTX_DATA_TYPE_NULL = 5,
- AGENTX_DATA_TYPE_OID = 6,
- AGENTX_DATA_TYPE_IPADDRESS = 64,
- AGENTX_DATA_TYPE_COUNTER32 = 65,
- AGENTX_DATA_TYPE_GAUGE32 = 66,
- AGENTX_DATA_TYPE_TIMETICKS = 67,
- AGENTX_DATA_TYPE_OPAQUE = 68,
- AGENTX_DATA_TYPE_COUNTER64 = 70,
- AGENTX_DATA_TYPE_NOSUCHOBJECT = 128,
- AGENTX_DATA_TYPE_NOSUCHINSTANCE = 129,
- AGENTX_DATA_TYPE_ENDOFMIBVIEW = 130
-};
-
-enum agentx_close_reason {
- AGENTX_CLOSE_OTHER = 1,
- AGENTX_CLOSEN_PARSEERROR = 2,
- AGENTX_CLOSE_PROTOCOLERROR = 3,
- AGENTX_CLOSE_TIMEOUTS = 4,
- AGENTX_CLOSE_SHUTDOWN = 5,
- AGENTX_CLOSE_BYMANAGER = 6
-};
-
-struct agentx {
- int ax_fd;
- enum agentx_byte_order ax_byteorder;
- uint8_t *ax_rbuf;
- size_t ax_rblen;
- size_t ax_rbsize;
- uint8_t *ax_wbuf;
- size_t ax_wblen;
- size_t ax_wbtlen;
- size_t ax_wbsize;
- uint32_t *ax_packetids;
- size_t ax_packetidsize;
+#include <stdint.h>
+#include <stddef.h>
+
+struct agentx;
+struct agentx_session;
+struct agentx_context;
+struct agentx_agentcaps;
+struct agentx_region;
+struct agentx_index;
+struct agentx_object;
+struct agentx_varbind;
+
+enum agentx_request_type {
+ AGENTX_REQUEST_TYPE_GET,
+ AGENTX_REQUEST_TYPE_GETNEXT,
+ AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
};
-#ifndef AGENTX_PRIMITIVE
-#define AGENTX_PRIMITIVE
-
+#define AGENTX_MASTER_PATH "/var/agentx/master"
#define AGENTX_OID_MAX_LEN 128
-
-struct agentx_oid {
- uint8_t aoi_include;
- uint32_t aoi_id[AGENTX_OID_MAX_LEN];
- size_t aoi_idlen;
-};
-
-struct agentx_ostring {
- unsigned char *aos_string;
- uint32_t aos_slen;
-};
-#endif
-
-struct agentx_searchrange {
- struct agentx_oid asr_start;
- struct agentx_oid asr_stop;
-};
-
-struct agentx_pdu_header {
- uint8_t aph_version;
- uint8_t aph_type;
- uint8_t aph_flags;
- uint8_t aph_reserved;
- uint32_t aph_sessionid;
- uint32_t aph_transactionid;
- uint32_t aph_packetid;
- uint32_t aph_plength;
-};
-
-struct agentx_varbind {
- enum agentx_data_type avb_type;
- struct agentx_oid avb_oid;
- union agentx_data {
- uint32_t avb_uint32;
- uint64_t avb_uint64;
- struct agentx_ostring avb_ostring;
- struct agentx_oid avb_oid;
- } avb_data;
-};
-
-struct agentx_pdu {
- struct agentx_pdu_header ap_header;
- struct agentx_ostring ap_context;
- union {
- struct agentx_pdu_searchrangelist {
- size_t ap_nsr;
- struct agentx_searchrange *ap_sr;
- } ap_srl;
- struct agentx_pdu_getbulk {
- uint16_t ap_nonrep;
- uint16_t ap_maxrep;
- struct agentx_pdu_searchrangelist ap_srl;
- } ap_getbulk;
- struct agentx_pdu_varbindlist {
- struct agentx_varbind *ap_varbind;
- size_t ap_nvarbind;
- } ap_vbl;
- struct agentx_pdu_response {
- uint32_t ap_uptime;
- enum agentx_pdu_error ap_error;
- uint16_t ap_index;
- struct agentx_varbind *ap_varbindlist;
- size_t ap_nvarbind;
- } ap_response;
- void *ap_raw;
- } ap_payload;
-};
-
-struct agentx *agentx_new(int);
+#define AGENTX_OID_INDEX_MAX_LEN 10
+#define AGENTX_MIB2 1, 3, 6, 1, 2, 1
+#define AGENTX_ENTERPRISES 1, 3, 6, 1, 4, 1
+#define AGENTX_OID(...) (uint32_t []) { __VA_ARGS__ }, \
+ (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t))
+
+extern void (*agentx_log_fatal)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2)));
+extern void (*agentx_log_warn)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2)));
+extern void (*agentx_log_info)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2)));
+extern void (*agentx_log_debug)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2)));
+
+struct agentx *agentx(void (*)(struct agentx *, void *, int), void *);
+void agentx_connect(struct agentx *, int);
+void agentx_read(struct agentx *);
+void agentx_write(struct agentx *);
+extern void (*agentx_wantwrite)(struct agentx *, int);
void agentx_free(struct agentx *);
-struct agentx_pdu *agentx_recv(struct agentx *);
-ssize_t agentx_send(struct agentx *);
-uint32_t agentx_open(struct agentx *, uint8_t, struct agentx_oid *,
- struct agentx_ostring *);
-uint32_t agentx_close(struct agentx *, uint32_t, enum agentx_close_reason);
-uint32_t agentx_indexallocate(struct agentx *, uint8_t, uint32_t,
- struct agentx_ostring *, struct agentx_varbind *, size_t);
-uint32_t agentx_indexdeallocate(struct agentx *, uint32_t,
- struct agentx_ostring *, struct agentx_varbind *, size_t);
-uint32_t agentx_addagentcaps(struct agentx *, uint32_t, struct agentx_ostring *,
- struct agentx_oid *, struct agentx_ostring *);
-uint32_t agentx_removeagentcaps(struct agentx *, uint32_t,
- struct agentx_ostring *, struct agentx_oid *);
-uint32_t agentx_register(struct agentx *, uint8_t, uint32_t,
- struct agentx_ostring *, uint8_t, uint8_t, uint8_t, struct agentx_oid *,
- uint32_t);
-uint32_t agentx_unregister(struct agentx *, uint32_t, struct agentx_ostring *,
- uint8_t, uint8_t, struct agentx_oid *, uint32_t);
-int agentx_response(struct agentx *, uint32_t, uint32_t, uint32_t,
- struct agentx_ostring *, uint32_t, uint16_t, uint16_t,
- struct agentx_varbind *, size_t);
-void agentx_pdu_free(struct agentx_pdu *);
-void agentx_varbind_free(struct agentx_varbind *);
-const char *agentx_error2string(enum agentx_pdu_error);
-const char *agentx_pdutype2string(enum agentx_pdu_type);
-const char *agentx_oid2string(struct agentx_oid *);
-const char *agentx_oidrange2string(struct agentx_oid *, uint8_t, uint32_t);
-const char *agentx_varbind2string(struct agentx_varbind *);
-const char *agentx_closereason2string(enum agentx_close_reason);
-int agentx_oid_cmp(struct agentx_oid *, struct agentx_oid *);
-int agentx_oid_add(struct agentx_oid *, uint32_t);
+struct agentx_session *agentx_session(struct agentx *,
+ uint32_t[], size_t, const char *, uint8_t);
+void agentx_session_free(struct agentx_session *);
+struct agentx_context *agentx_context(struct agentx_session *,
+ const char *);
+struct agentx_object *agentx_context_object_find(
+ struct agentx_context *, const uint32_t[], size_t, int, int);
+struct agentx_object *agentx_context_object_nfind(
+ struct agentx_context *, const uint32_t[], size_t, int, int);
+uint32_t agentx_context_uptime(struct agentx_context *);
+void agentx_context_free(struct agentx_context *);
+struct agentx_agentcaps *agentx_agentcaps(struct agentx_context *,
+ uint32_t[], size_t, const char *);
+void agentx_agentcaps_free(struct agentx_agentcaps *);
+struct agentx_region *agentx_region(struct agentx_context *,
+ uint32_t[], size_t, uint8_t);
+void agentx_region_free(struct agentx_region *);
+struct agentx_index *agentx_index_integer_new(struct agentx_region *,
+ uint32_t[], size_t);
+struct agentx_index *agentx_index_integer_any(struct agentx_region *,
+ uint32_t[], size_t);
+struct agentx_index *agentx_index_integer_value(struct agentx_region *,
+ uint32_t[], size_t, uint32_t);
+struct agentx_index *agentx_index_integer_dynamic(
+ struct agentx_region *, uint32_t[], size_t);
+struct agentx_index *agentx_index_string_dynamic(
+ struct agentx_region *, uint32_t[], size_t);
+struct agentx_index *agentx_index_nstring_dynamic(
+ struct agentx_region *, uint32_t[], size_t, size_t);
+struct agentx_index *agentx_index_oid_dynamic(struct agentx_region *,
+ uint32_t[], size_t);
+struct agentx_index *agentx_index_noid_dynamic(struct agentx_region *,
+ uint32_t[], size_t, size_t);
+struct agentx_index *agentx_index_ipaddress_dynamic(
+ struct agentx_region *, uint32_t[], size_t);
+void agentx_index_free(struct agentx_index *);
+struct agentx_object *agentx_object(struct agentx_region *, uint32_t[],
+ size_t, struct agentx_index *[], size_t, int,
+ void (*)(struct agentx_varbind *));
+void agentx_object_free(struct agentx_object *);
+
+void agentx_varbind_integer(struct agentx_varbind *, uint32_t);
+void agentx_varbind_string(struct agentx_varbind *, const char *);
+void agentx_varbind_nstring(struct agentx_varbind *,
+ const unsigned char *, size_t);
+void agentx_varbind_printf(struct agentx_varbind *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_varbind_null(struct agentx_varbind *);
+void agentx_varbind_oid(struct agentx_varbind *, const uint32_t[],
+ size_t);
+void agentx_varbind_object(struct agentx_varbind *,
+ struct agentx_object *);
+void agentx_varbind_index(struct agentx_varbind *,
+ struct agentx_index *);
+void agentx_varbind_ipaddress(struct agentx_varbind *,
+ const struct in_addr *);
+void agentx_varbind_counter32(struct agentx_varbind *, uint32_t);
+void agentx_varbind_gauge32(struct agentx_varbind *, uint32_t);
+void agentx_varbind_timeticks(struct agentx_varbind *, uint32_t);
+void agentx_varbind_opaque(struct agentx_varbind *, const char *, size_t);
+void agentx_varbind_counter64(struct agentx_varbind *, uint64_t);
+void agentx_varbind_notfound(struct agentx_varbind *);
+void agentx_varbind_error(struct agentx_varbind *);
+
+enum agentx_request_type agentx_varbind_request(
+ struct agentx_varbind *);
+struct agentx_object *
+ agentx_varbind_get_object(struct agentx_varbind *);
+uint32_t agentx_varbind_get_index_integer(struct agentx_varbind *,
+ struct agentx_index *);
+const unsigned char *agentx_varbind_get_index_string(
+ struct agentx_varbind *, struct agentx_index *, size_t *, int *);
+const uint32_t *agentx_varbind_get_index_oid(struct agentx_varbind *,
+ struct agentx_index *, size_t *, int *);
+const struct in_addr *agentx_varbind_get_index_ipaddress(
+ struct agentx_varbind *, struct agentx_index *);
+void agentx_varbind_set_index_integer(struct agentx_varbind *,
+ struct agentx_index *, uint32_t);
+void agentx_varbind_set_index_string(struct agentx_varbind *,
+ struct agentx_index *, const char *);
+void agentx_varbind_set_index_nstring(struct agentx_varbind *,
+ struct agentx_index *, const unsigned char *, size_t);
+void agentx_varbind_set_index_oid(struct agentx_varbind *,
+ struct agentx_index *, const uint32_t *, size_t);
+void agentx_varbind_set_index_object(struct agentx_varbind *,
+ struct agentx_index *, struct agentx_object *);
+void agentx_varbind_set_index_ipaddress(struct agentx_varbind *,
+ struct agentx_index *, const struct in_addr *);
diff --git a/lib/libagentx/agentx_internal.h b/lib/libagentx/agentx_internal.h
new file mode 100644
index 00000000000..f8d7a8ce2d9
--- /dev/null
+++ b/lib/libagentx/agentx_internal.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/tree.h>
+
+#include "ax.h"
+
+enum agentx_cstate { /* Current state */
+ AX_CSTATE_CLOSE, /* Closed */
+ AX_CSTATE_WAITOPEN, /* Connection requested */
+ AX_CSTATE_OPEN, /* Open */
+ AX_CSTATE_WAITCLOSE /* Close requested */
+};
+
+enum agentx_dstate { /* Desired state */
+ AX_DSTATE_OPEN, /* Open */
+ AX_DSTATE_CLOSE /* Close/free */
+};
+
+struct agentx {
+ void (*ax_nofd)(struct agentx *, void *, int);
+ void *ax_cookie;
+ int ax_fd;
+ enum agentx_cstate ax_cstate;
+ enum agentx_dstate ax_dstate;
+ struct ax *ax_ax;
+ TAILQ_HEAD(, agentx_session) ax_sessions;
+ TAILQ_HEAD(, agentx_get) ax_getreqs;
+ RB_HEAD(ax_requests, agentx_request) ax_requests;
+};
+
+struct agentx_session {
+ struct agentx *axs_ax;
+ uint32_t axs_id;
+ uint32_t axs_timeout;
+ struct ax_oid axs_oid;
+ struct ax_ostring axs_descr;
+ enum agentx_cstate axs_cstate;
+ enum agentx_dstate axs_dstate;
+ uint32_t axs_packetid;
+ TAILQ_HEAD(, agentx_context) axs_contexts;
+ TAILQ_ENTRY(agentx_session) axs_ax_sessions;
+};
+
+struct agentx_context {
+ struct agentx_session *axc_axs;
+ int axc_name_default;
+ struct ax_ostring axc_name;
+ uint32_t axc_sysuptime;
+ struct timespec axc_sysuptimespec;
+ enum agentx_cstate axc_cstate;
+ enum agentx_dstate axc_dstate;
+ TAILQ_HEAD(, agentx_agentcaps) axc_agentcaps;
+ TAILQ_HEAD(, agentx_region) axc_regions;
+ RB_HEAD(axc_objects, agentx_object) axc_objects;
+ TAILQ_ENTRY(agentx_context) axc_axs_contexts;
+};
+
+struct agentx_get {
+ struct agentx_context *axg_axc;
+ int axg_fd; /* Only used for logging */
+ uint32_t axg_sessionid;
+ uint32_t axg_transactionid;
+ uint32_t axg_packetid;
+ int axg_context_default;
+ struct ax_ostring axg_context;
+ enum ax_pdu_type axg_type;
+ uint16_t axg_nonrep;
+ uint16_t axg_maxrep;
+ size_t axg_nvarbind;
+ struct agentx_varbind *axg_varbind;
+ TAILQ_ENTRY(agentx_get) axg_ax_getreqs;
+};
+
+__dead void agentx_log_ax_fatalx(struct agentx *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_ax_warn(struct agentx *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_ax_warnx(struct agentx *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_ax_info(struct agentx *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_ax_debug(struct agentx *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+__dead void agentx_log_axs_fatalx(struct agentx_session *, const char *,
+ ...) __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axs_warnx(struct agentx_session *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axs_warn(struct agentx_session *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axs_info(struct agentx_session *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+__dead void agentx_log_axc_fatalx(struct agentx_context *, const char *,
+ ...) __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axc_warnx(struct agentx_context *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axc_warn(struct agentx_context *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axc_info(struct agentx_context *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axc_debug(struct agentx_context *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+__dead void agentx_log_axg_fatalx(struct agentx_get *, const char *,
+ ...) __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axg_warnx(struct agentx_get *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axg_warn(struct agentx_get *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void agentx_log_axg_debug(struct agentx_get *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
diff --git a/lib/libagentx/agentx_log.c b/lib/libagentx/agentx_log.c
new file mode 100644
index 00000000000..fd01b626bcd
--- /dev/null
+++ b/lib/libagentx/agentx_log.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "agentx_internal.h"
+
+#define AGENTX_CONTEXT_NAME(axc) (axc->axc_name_default ? "<default>" : \
+ (char *)axc->axc_name.aos_string)
+#define AGENTX_GET_CTXNAME(axg) (axg->axg_context_default ? "<default>" : \
+ (char *)axg->axg_context.aos_string)
+
+enum agentx_log_type {
+ AGENTX_LOG_TYPE_FATAL,
+ AGENTX_LOG_TYPE_WARN,
+ AGENTX_LOG_TYPE_INFO,
+ AGENTX_LOG_TYPE_DEBUG
+};
+
+void (*agentx_log_fatal)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2))) = NULL;
+void (*agentx_log_warn)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2))) = NULL;
+void (*agentx_log_info)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2))) = NULL;
+void (*agentx_log_debug)(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2))) = NULL;
+
+
+static void
+agentx_log_do(enum agentx_log_type, const char *, va_list, int,
+ struct agentx *, struct agentx_session *, struct agentx_context *,
+ struct agentx_get *);
+
+void
+agentx_log_ax_fatalx(struct agentx *ax, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_FATAL, fmt, ap, 0, ax, NULL, NULL,
+ NULL);
+ va_end(ap);
+ abort();
+}
+
+void
+agentx_log_ax_warn(struct agentx *ax, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 1, ax, NULL, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_ax_warnx(struct agentx *ax, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 0, ax, NULL, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_ax_info(struct agentx *ax, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_INFO, fmt, ap, 0, ax, NULL, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_ax_debug(struct agentx *ax, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_DEBUG, fmt, ap, 0, ax, NULL, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axs_fatalx(struct agentx_session *axs, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_FATAL, fmt, ap, 0, NULL, axs, NULL,
+ NULL);
+ va_end(ap);
+ abort();
+}
+
+void
+agentx_log_axs_warnx(struct agentx_session *axs, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 0, NULL, axs, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axs_warn(struct agentx_session *axs, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 1, NULL, axs, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axs_info(struct agentx_session *axs, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_INFO, fmt, ap, 0, NULL, axs, NULL,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axc_fatalx(struct agentx_context *axc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_FATAL, fmt, ap, 0, NULL, NULL, axc,
+ NULL);
+ va_end(ap);
+ abort();
+}
+
+void
+agentx_log_axc_warnx(struct agentx_context *axc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 0, NULL, NULL, axc,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axc_warn(struct agentx_context *axc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 1, NULL, NULL, axc,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axc_info(struct agentx_context *axc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_INFO, fmt, ap, 0, NULL, NULL, axc,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axc_debug(struct agentx_context *axc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_DEBUG, fmt, ap, 0, NULL, NULL, axc,
+ NULL);
+ va_end(ap);
+}
+
+void
+agentx_log_axg_fatalx(struct agentx_get *axg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_FATAL, fmt, ap, 0, NULL, NULL, NULL,
+ axg);
+ va_end(ap);
+ abort();
+}
+
+void
+agentx_log_axg_warnx(struct agentx_get *axg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 0, NULL, NULL, NULL,
+ axg);
+ va_end(ap);
+}
+
+void
+agentx_log_axg_warn(struct agentx_get *axg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_WARN, fmt, ap, 1, NULL, NULL, NULL,
+ axg);
+ va_end(ap);
+}
+
+void
+agentx_log_axg_debug(struct agentx_get *axg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ agentx_log_do(AGENTX_LOG_TYPE_DEBUG, fmt, ap, 0, NULL, NULL, NULL,
+ axg);
+ va_end(ap);
+}
+
+static void
+agentx_log_do(enum agentx_log_type type, const char *fmt, va_list ap,
+ int useerrno, struct agentx *ax, struct agentx_session *axs,
+ struct agentx_context *axc, struct agentx_get *axg)
+{
+ void (*agentx_log)(const char *, ...);
+ char buf[1500];
+
+ if (type == AGENTX_LOG_TYPE_FATAL)
+ agentx_log = agentx_log_fatal;
+ else if (type == AGENTX_LOG_TYPE_WARN)
+ agentx_log = agentx_log_warn;
+ else if (type == AGENTX_LOG_TYPE_INFO)
+ agentx_log = agentx_log_info;
+ else
+ agentx_log = agentx_log_debug;
+ if (agentx_log == NULL)
+ return;
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+ if (axg != NULL) {
+ if (useerrno)
+ agentx_log("[fd:%d sess:%u ctx:%s trid:%u pid:%u]: "
+ "%s: %s", axg->axg_fd, axg->axg_sessionid,
+ AGENTX_GET_CTXNAME(axg), axg->axg_transactionid,
+ axg->axg_packetid, buf, strerror(errno));
+ else
+ agentx_log("[fd:%d sess:%u ctx:%s trid:%u pid:%u]: "
+ "%s", axg->axg_fd, axg->axg_sessionid,
+ AGENTX_GET_CTXNAME(axg), axg->axg_transactionid,
+ axg->axg_packetid, buf);
+ } else if (axc != NULL) {
+ axs = axc->axc_axs;
+ ax = axs->axs_ax;
+ if (useerrno)
+ agentx_log("[fd:%d sess:%u ctx:%s]: %s: %s",
+ ax->ax_fd, axs->axs_id, AGENTX_CONTEXT_NAME(axc),
+ buf, strerror(errno));
+ else
+ agentx_log("[fd:%d sess:%u ctx:%s]: %s", ax->ax_fd,
+ axs->axs_id, AGENTX_CONTEXT_NAME(axc), buf);
+ } else if (axs != NULL) {
+ ax = axs->axs_ax;
+ if (useerrno)
+ agentx_log("[fd:%d sess:%u]: %s: %s", ax->ax_fd,
+ axs->axs_id, buf, strerror(errno));
+ else
+ agentx_log("[fd:%d sess:%u]: %s", ax->ax_fd,
+ axs->axs_id, buf);
+ } else if (ax->ax_fd == -1) {
+ if (useerrno)
+ agentx_log("%s: %s", buf, strerror(errno));
+ else
+ agentx_log("%s", buf);
+ } else {
+ if (useerrno)
+ agentx_log("[fd:%d]: %s: %s", ax->ax_fd, buf,
+ strerror(errno));
+ else
+ agentx_log("[fd:%d]: %s", ax->ax_fd, buf);
+ }
+}
diff --git a/lib/libagentx/ax.c b/lib/libagentx/ax.c
new file mode 100644
index 00000000000..8a287040d7b
--- /dev/null
+++ b/lib/libagentx/ax.c
@@ -0,0 +1,1359 @@
+/*
+ * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <endian.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "ax.h"
+
+#define AX_PDU_HEADER 20
+
+static int ax_pdu_need(struct ax *, size_t);
+static int ax_pdu_header(struct ax *,
+ enum ax_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t,
+ struct ax_ostring *);
+static uint32_t ax_packetid(struct ax *);
+static uint32_t ax_pdu_queue(struct ax *);
+static int ax_pdu_add_uint16(struct ax *, uint16_t);
+static int ax_pdu_add_uint32(struct ax *, uint32_t);
+static int ax_pdu_add_uint64(struct ax *, uint64_t);
+static int ax_pdu_add_oid(struct ax *, struct ax_oid *, int);
+static int ax_pdu_add_str(struct ax *, struct ax_ostring *);
+static int ax_pdu_add_varbindlist( struct ax *, struct ax_varbind *,
+ size_t);
+static uint16_t ax_pdutoh16(struct ax_pdu_header *, uint8_t *);
+static uint32_t ax_pdutoh32(struct ax_pdu_header *, uint8_t *);
+static uint64_t ax_pdutoh64(struct ax_pdu_header *, uint8_t *);
+static ssize_t ax_pdutooid(struct ax_pdu_header *, struct ax_oid *,
+ uint8_t *, size_t);
+static ssize_t ax_pdutoostring(struct ax_pdu_header *,
+ struct ax_ostring *, uint8_t *, size_t);
+static ssize_t ax_pdutovarbind(struct ax_pdu_header *,
+ struct ax_varbind *, uint8_t *, size_t);
+
+struct ax *
+ax_new(int fd)
+{
+ struct ax *ax;
+
+ if (fd == -1) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if ((ax = calloc(1, sizeof(*ax))) == NULL)
+ return NULL;
+ ax->ax_fd = fd;
+ if ((ax->ax_rbuf = malloc(512)) == NULL)
+ goto fail;
+ ax->ax_rbsize = 512;
+ ax->ax_byteorder = AX_BYTE_ORDER_NATIVE;
+
+ return ax;
+
+fail:
+ free(ax);
+ return NULL;
+}
+
+void
+ax_free(struct ax *ax)
+{
+ if (ax == NULL)
+ return;
+ close(ax->ax_fd);
+ free(ax->ax_rbuf);
+ free(ax->ax_wbuf);
+ free(ax->ax_packetids);
+ free(ax);
+}
+
+struct ax_pdu *
+ax_recv(struct ax *ax)
+{
+ struct ax_pdu *pdu;
+ struct ax_pdu_header header;
+ struct ax_pdu_response *response;
+ struct ax_varbind *varbind;
+ struct ax_pdu_searchrangelist *srl = NULL;
+ struct ax_pdu_varbindlist *vbl;
+ struct ax_searchrange *sr;
+ size_t rbsize, packetidx = 0, i, rawlen;
+ ssize_t nread;
+ uint8_t *u8;
+ uint8_t *rbuf;
+ int found;
+
+ /* Only read a single packet at a time to make sure libevent triggers */
+ if (ax->ax_rblen < AX_PDU_HEADER) {
+ if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
+ AX_PDU_HEADER - ax->ax_rblen)) == 0) {
+ errno = ECONNRESET;
+ return NULL;
+ }
+ if (nread == -1)
+ return NULL;
+ ax->ax_rblen += nread;
+ if (ax->ax_rblen < AX_PDU_HEADER) {
+ errno = EAGAIN;
+ return NULL;
+ }
+ }
+ u8 = ax->ax_rbuf;
+ header.aph_version = *u8++;
+ header.aph_type = *u8++;
+ header.aph_flags = *u8++;
+ u8++;
+ header.aph_sessionid = ax_pdutoh32(&header, u8);
+ u8 += 4;
+ header.aph_transactionid = ax_pdutoh32(&header, u8);
+ u8 += 4;
+ header.aph_packetid = ax_pdutoh32(&header, u8);
+ u8 += 4;
+ header.aph_plength = ax_pdutoh32(&header, u8);
+
+ if (header.aph_version != 1) {
+ errno = EPROTO;
+ return NULL;
+ }
+ if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) {
+ if (AX_PDU_HEADER + header.aph_plength > ax->ax_rbsize) {
+ rbsize = (((AX_PDU_HEADER + header.aph_plength)
+ / 512) + 1) * 512;
+ if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize,
+ rbsize, sizeof(*rbuf))) == NULL)
+ return NULL;
+ ax->ax_rbsize = rbsize;
+ ax->ax_rbuf = rbuf;
+ }
+ nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
+ header.aph_plength - (ax->ax_rblen - AX_PDU_HEADER));
+ if (nread == 0)
+ errno = ECONNRESET;
+ if (nread <= 0)
+ return NULL;
+ ax->ax_rblen += nread;
+ if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) {
+ errno = EAGAIN;
+ return NULL;
+ }
+ }
+
+ if ((pdu = calloc(1, sizeof(*pdu))) == NULL)
+ return NULL;
+
+ memcpy(&(pdu->ap_header), &header, sizeof(header));
+
+#if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE)
+ {
+ char chars[4];
+ int print = 1;
+
+ fprintf(stderr, "received packet:\n");
+ for (i = 0; i < pdu->ap_header.aph_plength + AX_PDU_HEADER;
+ i++) {
+ fprintf(stderr, "%02hhx ", ax->ax_rbuf[i]);
+ chars[i % 4] = ax->ax_rbuf[i];
+ if (!isprint(ax->ax_rbuf[i]))
+ print = 0;
+ if (i % 4 == 3) {
+ if (print)
+ fprintf(stderr, "%.4s", chars);
+ fprintf(stderr, "\n");
+ print = 1;
+ }
+ }
+ }
+#endif
+
+ u8 = (ax->ax_rbuf) + AX_PDU_HEADER;
+ rawlen = pdu->ap_header.aph_plength;
+ if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) {
+ nread = ax_pdutoostring(&header, &(pdu->ap_context), u8,
+ rawlen);
+ if (nread == -1)
+ goto fail;
+ rawlen -= nread;
+ u8 += nread;
+ }
+
+ switch (pdu->ap_header.aph_type) {
+ case AX_PDU_TYPE_GETBULK:
+ if (rawlen < 4) {
+ errno = EPROTO;
+ goto fail;
+ }
+ pdu->ap_payload.ap_getbulk.ap_nonrep =
+ ax_pdutoh16(&header, u8);
+ u8 += 2;
+ pdu->ap_payload.ap_getbulk.ap_maxrep =
+ ax_pdutoh16(&header, u8);
+ u8 += 2;
+ srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
+ rawlen -= 4;
+ /* FALLTHROUGH */
+ case AX_PDU_TYPE_GET:
+ case AX_PDU_TYPE_GETNEXT:
+ if (pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK)
+ srl = &(pdu->ap_payload.ap_srl);
+ while (rawlen > 0 ) {
+ srl->ap_nsr++;
+ sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr));
+ if (sr == NULL)
+ goto fail;
+ srl->ap_sr = sr;
+ sr += (srl->ap_nsr - 1);
+ if ((nread = ax_pdutooid(&header, &(sr->asr_start),
+ u8, rawlen)) == -1)
+ goto fail;
+ rawlen -= nread;
+ u8 += nread;
+ if ((nread = ax_pdutooid(&header, &(sr->asr_stop),
+ u8, rawlen)) == -1)
+ goto fail;
+ rawlen -= nread;
+ u8 += nread;
+ }
+ break;
+ case AX_PDU_TYPE_TESTSET:
+ vbl = &(pdu->ap_payload.ap_vbl);
+ while (rawlen > 0) {
+ varbind = recallocarray(vbl->ap_varbind,
+ vbl->ap_nvarbind, vbl->ap_nvarbind + 1,
+ sizeof(*(vbl->ap_varbind)));
+ if (varbind == NULL)
+ goto fail;
+ vbl->ap_varbind = varbind;
+ nread = ax_pdutovarbind(&header,
+ &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen);
+ if (nread == -1)
+ goto fail;
+ vbl->ap_nvarbind++;
+ u8 += nread;
+ rawlen -= nread;
+ }
+ break;
+ case AX_PDU_TYPE_COMMITSET:
+ case AX_PDU_TYPE_UNDOSET:
+ case AX_PDU_TYPE_CLEANUPSET:
+ if (rawlen != 0) {
+ errno = EPROTO;
+ goto fail;
+ }
+ break;
+ case AX_PDU_TYPE_RESPONSE:
+ if (ax->ax_packetids != NULL) {
+ found = 0;
+ for (i = 0; ax->ax_packetids[i] != 0; i++) {
+ if (ax->ax_packetids[i] ==
+ pdu->ap_header.aph_packetid) {
+ packetidx = i;
+ found = 1;
+ }
+ }
+ if (found) {
+ ax->ax_packetids[packetidx] =
+ ax->ax_packetids[i - 1];
+ ax->ax_packetids[i - 1] = 0;
+ } else {
+ errno = EPROTO;
+ goto fail;
+ }
+ }
+ if (rawlen < 8) {
+ errno = EPROTO;
+ goto fail;
+ }
+ response = &(pdu->ap_payload.ap_response);
+ response->ap_uptime = ax_pdutoh32(&header, u8);
+ u8 += 4;
+ response->ap_error = ax_pdutoh16(&header, u8);
+ u8 += 2;
+ response->ap_index = ax_pdutoh16(&header, u8);
+ u8 += 2;
+ rawlen -= 8;
+ while (rawlen > 0) {
+ varbind = recallocarray(response->ap_varbindlist,
+ response->ap_nvarbind, response->ap_nvarbind + 1,
+ sizeof(*(response->ap_varbindlist)));
+ if (varbind == NULL)
+ goto fail;
+ response->ap_varbindlist = varbind;
+ nread = ax_pdutovarbind(&header,
+ &(response->ap_varbindlist[response->ap_nvarbind]),
+ u8, rawlen);
+ if (nread == -1)
+ goto fail;
+ response->ap_nvarbind++;
+ u8 += nread;
+ rawlen -= nread;
+ }
+ break;
+ default:
+ pdu->ap_payload.ap_raw = malloc(pdu->ap_header.aph_plength);
+ if (pdu->ap_payload.ap_raw == NULL)
+ goto fail;
+ memcpy(pdu->ap_payload.ap_raw, ax->ax_rbuf + AX_PDU_HEADER,
+ pdu->ap_header.aph_plength);
+ break;
+ }
+
+ ax->ax_rblen = 0;
+
+ return pdu;
+fail:
+ ax_pdu_free(pdu);
+ return NULL;
+}
+
+static int
+ax_pdu_need(struct ax *ax, size_t need)
+{
+ uint8_t *wbuf;
+ size_t wbsize;
+
+ if (ax->ax_wbtlen >= ax->ax_wbsize) {
+ wbsize = ((ax->ax_wbtlen / 512) + 1) * 512;
+ wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1);
+ if (wbuf == NULL) {
+ ax->ax_wbtlen = ax->ax_wblen;
+ return -1;
+ }
+ ax->ax_wbsize = wbsize;
+ ax->ax_wbuf = wbuf;
+ }
+
+ return 0;
+}
+
+ssize_t
+ax_send(struct ax *ax)
+{
+ ssize_t nwrite;
+
+ if (ax->ax_wblen != ax->ax_wbtlen) {
+ errno = EALREADY;
+ return -1;
+ }
+
+ if (ax->ax_wblen == 0)
+ return 0;
+
+#if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE)
+ {
+ size_t i;
+ char chars[4];
+ int print = 1;
+
+ fprintf(stderr, "sending packet:\n");
+ for (i = 0; i < ax->ax_wblen; i++) {
+ fprintf(stderr, "%02hhx ", ax->ax_wbuf[i]);
+ chars[i % 4] = ax->ax_wbuf[i];
+ if (!isprint(ax->ax_wbuf[i]))
+ print = 0;
+ if (i % 4 == 3) {
+ if (print)
+ fprintf(stderr, "%.4s", chars);
+ fprintf(stderr, "\n");
+ print = 1;
+ }
+ }
+ }
+#endif
+
+ if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen,
+ MSG_NOSIGNAL | MSG_DONTWAIT)) == -1)
+ return -1;
+
+ memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite);
+ ax->ax_wblen -= nwrite;
+ ax->ax_wbtlen = ax->ax_wblen;
+
+ return ax->ax_wblen;
+}
+
+uint32_t
+ax_open(struct ax *ax, uint8_t timeout, struct ax_oid *oid,
+ struct ax_ostring *descr)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_OPEN, 0, 0, 0, 0,
+ NULL) == -1)
+ return 0;
+ ax_pdu_need(ax, 4);
+ ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
+ memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
+ ax->ax_wbtlen += 3;
+ if (ax_pdu_add_oid(ax, oid, 0) == -1)
+ return 0;
+ if (ax_pdu_add_str(ax, descr) == -1)
+ return 0;
+
+ return ax_pdu_queue(ax);
+}
+
+uint32_t
+ax_close(struct ax *ax, uint32_t sessionid,
+ enum ax_close_reason reason)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_CLOSE, 0, sessionid, 0, 0,
+ NULL) == -1)
+ return 0;
+
+ if (ax_pdu_need(ax, 4) == -1)
+ return 0;
+ ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason;
+ memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
+ ax->ax_wbtlen += 3;
+
+ return ax_pdu_queue(ax);
+}
+
+uint32_t
+ax_indexallocate(struct ax *ax, uint8_t flags, uint32_t sessionid,
+ struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb)
+{
+ if (flags & ~(AX_PDU_FLAG_NEW_INDEX | AX_PDU_FLAG_ANY_INDEX)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXALLOCATE, flags,
+ sessionid, 0, 0, context) == -1)
+ return 0;
+
+ if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
+ return 0;
+
+ return ax_pdu_queue(ax);
+}
+
+uint32_t
+ax_indexdeallocate(struct ax *ax, uint32_t sessionid,
+ struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXDEALLOCATE, 0,
+ sessionid, 0, 0, context) == -1)
+ return 0;
+
+ if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
+ return 0;
+
+ return ax_pdu_queue(ax);
+}
+
+uint32_t
+ax_addagentcaps(struct ax *ax, uint32_t sessionid,
+ struct ax_ostring *context, struct ax_oid *id,
+ struct ax_ostring *descr)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_ADDAGENTCAPS, 0,
+ sessionid, 0, 0, context) == -1)
+ return 0;
+ if (ax_pdu_add_oid(ax, id, 0) == -1)
+ return 0;
+ if (ax_pdu_add_str(ax, descr) == -1)
+ return 0;
+
+ return ax_pdu_queue(ax);
+}
+
+uint32_t
+ax_removeagentcaps(struct ax *ax, uint32_t sessionid,
+ struct ax_ostring *context, struct ax_oid *id)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_REMOVEAGENTCAPS, 0,
+ sessionid, 0, 0, context) == -1)
+ return 0;
+ if (ax_pdu_add_oid(ax, id, 0) == -1)
+ return 0;
+
+ return ax_pdu_queue(ax);
+
+}
+
+uint32_t
+ax_register(struct ax *ax, uint8_t flags, uint32_t sessionid,
+ struct ax_ostring *context, uint8_t timeout, uint8_t priority,
+ uint8_t range_subid, struct ax_oid *subtree, uint32_t upperbound)
+{
+ if (flags & ~(AX_PDU_FLAG_INSTANCE_REGISTRATION)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (ax_pdu_header(ax, AX_PDU_TYPE_REGISTER, flags,
+ sessionid, 0, 0, context) == -1)
+ return 0;
+
+ if (ax_pdu_need(ax, 4) == -1)
+ return 0;
+ ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
+ ax->ax_wbuf[ax->ax_wbtlen++] = priority;
+ ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
+ ax->ax_wbuf[ax->ax_wbtlen++] = 0;
+ if (ax_pdu_add_oid(ax, subtree, 0) == -1)
+ return 0;
+ if (range_subid != 0) {
+ if (ax_pdu_add_uint32(ax, upperbound) == -1)
+ return 0;
+ }
+
+ return ax_pdu_queue(ax);
+}
+
+uint32_t
+ax_unregister(struct ax *ax, uint32_t sessionid,
+ struct ax_ostring *context, uint8_t priority, uint8_t range_subid,
+ struct ax_oid *subtree, uint32_t upperbound)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_UNREGISTER, 0,
+ sessionid, 0, 0, context) == -1)
+ return 0;
+
+ if (ax_pdu_need(ax, 4) == -1)
+ return 0;
+ ax->ax_wbuf[ax->ax_wbtlen++] = 0;
+ ax->ax_wbuf[ax->ax_wbtlen++] = priority;
+ ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
+ ax->ax_wbuf[ax->ax_wbtlen++] = 0;
+ if (ax_pdu_add_oid(ax, subtree, 0) == -1)
+ return 0;
+ if (range_subid != 0) {
+ if (ax_pdu_add_uint32(ax, upperbound) == -1)
+ return 0;
+ }
+
+ return ax_pdu_queue(ax);
+}
+
+int
+ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid,
+ uint32_t packetid, struct ax_ostring *context, uint32_t sysuptime,
+ uint16_t error, uint16_t index, struct ax_varbind *vblist, size_t nvb)
+{
+ if (ax_pdu_header(ax, AX_PDU_TYPE_RESPONSE, 0, sessionid,
+ transactionid, packetid, context) == -1)
+ return -1;
+
+ if (ax_pdu_add_uint32(ax, sysuptime) == -1 ||
+ ax_pdu_add_uint16(ax, error) == -1 ||
+ ax_pdu_add_uint16(ax, index) == -1)
+ return -1;
+
+ if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
+ return -1;
+ if (ax_pdu_queue(ax) == 0)
+ return -1;
+ return 0;
+}
+
+void
+ax_pdu_free(struct ax_pdu *pdu)
+{
+ size_t i;
+ struct ax_pdu_response *response;
+
+ if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT)
+ free(pdu->ap_context.aos_string);
+
+ switch (pdu->ap_header.aph_type) {
+ case AX_PDU_TYPE_GET:
+ case AX_PDU_TYPE_GETNEXT:
+ case AX_PDU_TYPE_GETBULK:
+ free(pdu->ap_payload.ap_srl.ap_sr);
+ break;
+ case AX_PDU_TYPE_RESPONSE:
+ response = &(pdu->ap_payload.ap_response);
+ for (i = 0; i < response->ap_nvarbind; i++)
+ ax_varbind_free(&(response->ap_varbindlist[i]));
+ free(response->ap_varbindlist);
+ break;
+ default:
+ free(pdu->ap_payload.ap_raw);
+ break;
+ }
+ free(pdu);
+}
+
+void
+ax_varbind_free(struct ax_varbind *varbind)
+{
+ switch (varbind->avb_type) {
+ case AX_DATA_TYPE_OCTETSTRING:
+ case AX_DATA_TYPE_IPADDRESS:
+ case AX_DATA_TYPE_OPAQUE:
+ free(varbind->avb_data.avb_ostring.aos_string);
+ break;
+ default:
+ break;
+ }
+}
+
+const char *
+ax_error2string(enum ax_pdu_error error)
+{
+ static char buffer[64];
+ switch (error) {
+ case AX_PDU_ERROR_NOERROR:
+ return "No error";
+ case AX_PDU_ERROR_GENERR:
+ return "Generic error";
+ case AX_PDU_ERROR_NOACCESS:
+ return "No access";
+ case AX_PDU_ERROR_WRONGTYPE:
+ return "Wrong type";
+ case AX_PDU_ERROR_WRONGLENGTH:
+ return "Wrong length";
+ case AX_PDU_ERROR_WRONGENCODING:
+ return "Wrong encoding";
+ case AX_PDU_ERROR_WRONGVALUE:
+ return "Wrong value";
+ case AX_PDU_ERROR_NOCREATION:
+ return "No creation";
+ case AX_PDU_ERROR_INCONSISTENTVALUE:
+ return "Inconsistent value";
+ case AX_PDU_ERROR_RESOURCEUNAVAILABLE:
+ return "Resource unavailable";
+ case AX_PDU_ERROR_COMMITFAILED:
+ return "Commit failed";
+ case AX_PDU_ERROR_UNDOFAILED:
+ return "Undo failed";
+ case AX_PDU_ERROR_NOTWRITABLE:
+ return "Not writable";
+ case AX_PDU_ERROR_INCONSISTENTNAME:
+ return "Inconsistent name";
+ case AX_PDU_ERROR_OPENFAILED:
+ return "Open Failed";
+ case AX_PDU_ERROR_NOTOPEN:
+ return "Not open";
+ case AX_PDU_ERROR_INDEXWRONGTYPE:
+ return "Index wrong type";
+ case AX_PDU_ERROR_INDEXALREADYALLOCATED:
+ return "Index already allocated";
+ case AX_PDU_ERROR_INDEXNONEAVAILABLE:
+ return "Index none available";
+ case AX_PDU_ERROR_INDEXNOTALLOCATED:
+ return "Index not allocated";
+ case AX_PDU_ERROR_UNSUPPORTEDCONETXT:
+ return "Unsupported context";
+ case AX_PDU_ERROR_DUPLICATEREGISTRATION:
+ return "Duplicate registration";
+ case AX_PDU_ERROR_UNKNOWNREGISTRATION:
+ return "Unkown registration";
+ case AX_PDU_ERROR_UNKNOWNAGENTCAPS:
+ return "Unknown agent capabilities";
+ case AX_PDU_ERROR_PARSEERROR:
+ return "Parse error";
+ case AX_PDU_ERROR_REQUESTDENIED:
+ return "Request denied";
+ case AX_PDU_ERROR_PROCESSINGERROR:
+ return "Processing error";
+ }
+ snprintf(buffer, sizeof(buffer), "Unknown error: %d", error);
+ return buffer;
+}
+
+const char *
+ax_pdutype2string(enum ax_pdu_type type)
+{
+ static char buffer[64];
+ switch(type) {
+ case AX_PDU_TYPE_OPEN:
+ return "agentx-Open-PDU";
+ case AX_PDU_TYPE_CLOSE:
+ return "agentx-Close-PDU";
+ case AX_PDU_TYPE_REGISTER:
+ return "agentx-Register-PDU";
+ case AX_PDU_TYPE_UNREGISTER:
+ return "agentx-Unregister-PDU";
+ case AX_PDU_TYPE_GET:
+ return "agentx-Get-PDU";
+ case AX_PDU_TYPE_GETNEXT:
+ return "agentx-GetNext-PDU";
+ case AX_PDU_TYPE_GETBULK:
+ return "agentx-GetBulk-PDU";
+ case AX_PDU_TYPE_TESTSET:
+ return "agentx-TestSet-PDU";
+ case AX_PDU_TYPE_COMMITSET:
+ return "agentx-CommitSet-PDU";
+ case AX_PDU_TYPE_UNDOSET:
+ return "agentx-UndoSet-PDU";
+ case AX_PDU_TYPE_CLEANUPSET:
+ return "agentx-CleanupSet-PDU";
+ case AX_PDU_TYPE_NOTIFY:
+ return "agentx-Notify-PDU";
+ case AX_PDU_TYPE_PING:
+ return "agentx-Ping-PDU";
+ case AX_PDU_TYPE_INDEXALLOCATE:
+ return "agentx-IndexAllocate-PDU";
+ case AX_PDU_TYPE_INDEXDEALLOCATE:
+ return "agentx-IndexDeallocate-PDU";
+ case AX_PDU_TYPE_ADDAGENTCAPS:
+ return "agentx-AddAgentCaps-PDU";
+ case AX_PDU_TYPE_REMOVEAGENTCAPS:
+ return "agentx-RemoveAgentCaps-PDU";
+ case AX_PDU_TYPE_RESPONSE:
+ return "agentx-Response-PDU";
+ }
+ snprintf(buffer, sizeof(buffer), "Unknown type: %d", type);
+ return buffer;
+}
+
+const char *
+ax_closereason2string(enum ax_close_reason reason)
+{
+ static char buffer[64];
+
+ switch (reason) {
+ case AX_CLOSE_OTHER:
+ return "Undefined reason";
+ case AX_CLOSEN_PARSEERROR:
+ return "Too many AgentX parse errors from peer";
+ case AX_CLOSE_PROTOCOLERROR:
+ return "Too many AgentX protocol errors from peer";
+ case AX_CLOSE_TIMEOUTS:
+ return "Too many timeouts waiting for peer";
+ case AX_CLOSE_SHUTDOWN:
+ return "shutting down";
+ case AX_CLOSE_BYMANAGER:
+ return "Manager shuts down";
+ }
+ snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason);
+ return buffer;
+}
+
+const char *
+ax_oid2string(struct ax_oid *oid)
+{
+ return ax_oidrange2string(oid, 0, 0);
+}
+
+const char *
+ax_oidrange2string(struct ax_oid *oid, uint8_t range_subid,
+ uint32_t upperbound)
+{
+ static char buf[1024];
+ char *p;
+ size_t i, rest;
+ int ret;
+
+ rest = sizeof(buf);
+ p = buf;
+ for (i = 0; i < oid->aoi_idlen; i++) {
+ if (range_subid != 0 && range_subid - 1 == (uint8_t)i)
+ ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i],
+ upperbound);
+ else
+ ret = snprintf(p, rest, ".%u", oid->aoi_id[i]);
+ if ((size_t) ret >= rest) {
+ snprintf(buf, sizeof(buf), "Couldn't parse oid");
+ return buf;
+ }
+ p += ret;
+ rest -= (size_t) ret;
+ }
+ return buf;
+}
+
+const char *
+ax_varbind2string(struct ax_varbind *vb)
+{
+ static char buf[1024];
+ char tmpbuf[1024];
+ size_t i, bufleft;
+ int ishex = 0;
+ char *p;
+ int ret;
+
+ switch (vb->avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+ snprintf(buf, sizeof(buf), "%s: (int)%u",
+ ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
+ break;
+ case AX_DATA_TYPE_OCTETSTRING:
+ for (i = 0;
+ i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) {
+ if (!isprint(vb->avb_data.avb_ostring.aos_string[i]))
+ ishex = 1;
+ }
+ if (ishex) {
+ p = tmpbuf;
+ bufleft = sizeof(tmpbuf);
+ for (i = 0;
+ i < vb->avb_data.avb_ostring.aos_slen; i++) {
+ ret = snprintf(p, bufleft, " %02hhX",
+ vb->avb_data.avb_ostring.aos_string[i]);
+ if (ret >= (int) bufleft) {
+ p = strrchr(p, ' ');
+ strlcpy(p, "...", 4);
+ break;
+ }
+ p += 3;
+ bufleft -= 3;
+ }
+ ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s",
+ ax_oid2string(&(vb->avb_oid)), tmpbuf);
+ if (ret >= (int) sizeof(buf)) {
+ p = strrchr(buf, ' ');
+ strlcpy(p, "...", 4);
+ }
+ } else {
+ ret = snprintf(buf, sizeof(buf), "%s: (string)",
+ ax_oid2string(&(vb->avb_oid)));
+ if (ret >= (int) sizeof(buf)) {
+ snprintf(buf, sizeof(buf), "<too large OID>: "
+ "(string)<too large string>");
+ break;
+ }
+ p = buf + ret;
+ bufleft = (int) sizeof(buf) - ret;
+ if (snprintf(p, bufleft, "%.*s",
+ vb->avb_data.avb_ostring.aos_slen,
+ vb->avb_data.avb_ostring.aos_string) >=
+ (int) bufleft) {
+ p = buf + sizeof(buf) - 4;
+ strlcpy(p, "...", 4);
+ }
+ }
+ break;
+ case AX_DATA_TYPE_NULL:
+ snprintf(buf, sizeof(buf), "%s: <null>",
+ ax_oid2string(&(vb->avb_oid)));
+ break;
+ case AX_DATA_TYPE_OID:
+ strlcpy(tmpbuf,
+ ax_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf));
+ snprintf(buf, sizeof(buf), "%s: (oid)%s",
+ ax_oid2string(&(vb->avb_oid)), tmpbuf);
+ break;
+ case AX_DATA_TYPE_IPADDRESS:
+ if (vb->avb_data.avb_ostring.aos_slen != 4) {
+ snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>",
+ ax_oid2string(&(vb->avb_oid)));
+ break;
+ }
+ if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string,
+ tmpbuf, sizeof(tmpbuf)) == NULL) {
+ snprintf(buf, sizeof(buf), "%s: (ipaddress)"
+ "<unparseable>: %s",
+ ax_oid2string(&(vb->avb_oid)),
+ strerror(errno));
+ break;
+ }
+ snprintf(buf, sizeof(buf), "%s: (ipaddress)%s",
+ ax_oid2string(&(vb->avb_oid)), tmpbuf);
+ break;
+ case AX_DATA_TYPE_COUNTER32:
+ snprintf(buf, sizeof(buf), "%s: (counter32)%u",
+ ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
+ break;
+ case AX_DATA_TYPE_GAUGE32:
+ snprintf(buf, sizeof(buf), "%s: (gauge32)%u",
+ ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
+ break;
+ case AX_DATA_TYPE_TIMETICKS:
+ snprintf(buf, sizeof(buf), "%s: (timeticks)%u",
+ ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
+ break;
+ case AX_DATA_TYPE_OPAQUE:
+ p = tmpbuf;
+ bufleft = sizeof(tmpbuf);
+ for (i = 0;
+ i < vb->avb_data.avb_ostring.aos_slen; i++) {
+ ret = snprintf(p, bufleft, " %02hhX",
+ vb->avb_data.avb_ostring.aos_string[i]);
+ if (ret >= (int) bufleft) {
+ p = strrchr(p, ' ');
+ strlcpy(p, "...", 4);
+ break;
+ }
+ p += 3;
+ bufleft -= 3;
+ }
+ ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s",
+ ax_oid2string(&(vb->avb_oid)), tmpbuf);
+ if (ret >= (int) sizeof(buf)) {
+ p = strrchr(buf, ' ');
+ strlcpy(p, "...", 4);
+ }
+ break;
+ case AX_DATA_TYPE_COUNTER64:
+ snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64,
+ ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64);
+ break;
+ case AX_DATA_TYPE_NOSUCHOBJECT:
+ snprintf(buf, sizeof(buf), "%s: <noSuchObject>",
+ ax_oid2string(&(vb->avb_oid)));
+ break;
+ case AX_DATA_TYPE_NOSUCHINSTANCE:
+ snprintf(buf, sizeof(buf), "%s: <noSuchInstance>",
+ ax_oid2string(&(vb->avb_oid)));
+ break;
+ case AX_DATA_TYPE_ENDOFMIBVIEW:
+ snprintf(buf, sizeof(buf), "%s: <endOfMibView>",
+ ax_oid2string(&(vb->avb_oid)));
+ break;
+ }
+ return buf;
+}
+
+int
+ax_oid_cmp(struct ax_oid *o1, struct ax_oid *o2)
+{
+ size_t i, min;
+
+ min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen;
+ for (i = 0; i < min; i++) {
+ if (o1->aoi_id[i] < o2->aoi_id[i])
+ return -1;
+ if (o1->aoi_id[i] > o2->aoi_id[i])
+ return 1;
+ }
+ /* o1 is parent of o2 */
+ if (o1->aoi_idlen < o2->aoi_idlen)
+ return -2;
+ /* o1 is child of o2 */
+ if (o1->aoi_idlen > o2->aoi_idlen)
+ return 2;
+ return 0;
+}
+
+int
+ax_oid_add(struct ax_oid *oid, uint32_t value)
+{
+ if (oid->aoi_idlen == AX_OID_MAX_LEN)
+ return -1;
+ oid->aoi_id[oid->aoi_idlen++] = value;
+ return 0;
+}
+
+static uint32_t
+ax_pdu_queue(struct ax *ax)
+{
+ struct ax_pdu_header header;
+ uint32_t packetid, plength;
+ size_t wbtlen = ax->ax_wbtlen;
+
+ header.aph_flags = ax->ax_byteorder == AX_BYTE_ORDER_BE ?
+ AX_PDU_FLAG_NETWORK_BYTE_ORDER : 0;
+ packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12]));
+ plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER;
+ ax->ax_wbtlen = ax->ax_wblen + 16;
+ (void)ax_pdu_add_uint32(ax, plength);
+
+ ax->ax_wblen = ax->ax_wbtlen = wbtlen;
+
+ return packetid;
+}
+
+static int
+ax_pdu_header(struct ax *ax, enum ax_pdu_type type, uint8_t flags,
+ uint32_t sessionid, uint32_t transactionid, uint32_t packetid,
+ struct ax_ostring *context)
+{
+ if (ax->ax_wblen != ax->ax_wbtlen) {
+ errno = EALREADY;
+ return -1;
+ }
+
+ ax->ax_wbtlen = ax->ax_wblen;
+ if (ax_pdu_need(ax, 4) == -1)
+ return -1;
+ ax->ax_wbuf[ax->ax_wbtlen++] = 1;
+ ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type;
+ if (context != NULL)
+ flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT;
+ if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
+ flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER;
+ ax->ax_wbuf[ax->ax_wbtlen++] = flags;
+ ax->ax_wbuf[ax->ax_wbtlen++] = 0;
+ if (packetid == 0)
+ packetid = ax_packetid(ax);
+ if (ax_pdu_add_uint32(ax, sessionid) == -1 ||
+ ax_pdu_add_uint32(ax, transactionid) == -1 ||
+ ax_pdu_add_uint32(ax, packetid) == -1 ||
+ ax_pdu_need(ax, 4) == -1)
+ return -1;
+ ax->ax_wbtlen += 4;
+ if (context != NULL) {
+ if (ax_pdu_add_str(ax, context) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint32_t
+ax_packetid(struct ax *ax)
+{
+ uint32_t packetid, *packetids;
+ size_t npackets = 0, i;
+ int found;
+
+ if (ax->ax_packetids != NULL) {
+ for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++)
+ continue;
+ }
+ if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) {
+ packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize,
+ ax->ax_packetidsize + 25, sizeof(*packetids));
+ if (packetids == NULL)
+ return 0;
+ ax->ax_packetidsize += 25;
+ ax->ax_packetids = packetids;
+ }
+ do {
+ found = 0;
+ packetid = arc4random();
+ for (i = 0; ax->ax_packetids[i] != 0; i++) {
+ if (ax->ax_packetids[i] == packetid) {
+ found = 1;
+ break;
+ }
+ }
+ } while (packetid == 0 || found);
+ ax->ax_packetids[npackets] = packetid;
+
+ return packetid;
+}
+
+static int
+ax_pdu_add_uint16(struct ax *ax, uint16_t value)
+{
+ if (ax_pdu_need(ax, sizeof(value)) == -1)
+ return -1;
+
+ if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
+ value = htobe16(value);
+ else
+ value = htole16(value);
+ memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
+ ax->ax_wbtlen += sizeof(value);
+ return 0;
+}
+
+static int
+ax_pdu_add_uint32(struct ax *ax, uint32_t value)
+{
+ if (ax_pdu_need(ax, sizeof(value)) == -1)
+ return -1;
+
+ if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
+ value = htobe32(value);
+ else
+ value = htole32(value);
+ memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
+ ax->ax_wbtlen += sizeof(value);
+ return 0;
+}
+
+static int
+ax_pdu_add_uint64(struct ax *ax, uint64_t value)
+{
+ if (ax_pdu_need(ax, sizeof(value)) == -1)
+ return -1;
+
+ if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
+ value = htobe64(value);
+ else
+ value = htole64(value);
+ memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
+ ax->ax_wbtlen += sizeof(value);
+ return 0;
+}
+
+
+static int
+ax_pdu_add_oid(struct ax *ax, struct ax_oid *oid, int include)
+{
+ static struct ax_oid nulloid = {0};
+ uint8_t prefix = 0, n_subid, i = 0;
+
+ n_subid = oid->aoi_idlen;
+
+ if (oid == NULL)
+ oid = &nulloid;
+
+ if (oid->aoi_idlen > 4 &&
+ oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 &&
+ oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 &&
+ oid->aoi_id[4] <= UINT8_MAX) {
+ prefix = oid->aoi_id[4];
+ i = 5;
+ }
+
+ if (ax_pdu_need(ax, 4) == -1)
+ return -1;
+ ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i;
+ ax->ax_wbuf[ax->ax_wbtlen++] = prefix;
+ ax->ax_wbuf[ax->ax_wbtlen++] = !!include;
+ ax->ax_wbuf[ax->ax_wbtlen++] = 0;
+
+ for (; i < n_subid; i++) {
+ if (ax_pdu_add_uint32(ax, oid->aoi_id[i]) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ax_pdu_add_str(struct ax *ax, struct ax_ostring *str)
+{
+ size_t length, zeroes;
+
+ if (ax_pdu_add_uint32(ax, str->aos_slen) == -1)
+ return -1;
+
+ if ((zeroes = (4 - (str->aos_slen % 4))) == 4)
+ zeroes = 0;
+ length = str->aos_slen + zeroes;
+ if (ax_pdu_need(ax, length) == -1)
+ return -1;
+
+ memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen);
+ ax->ax_wbtlen += str->aos_slen;
+ memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes);
+ ax->ax_wbtlen += zeroes;
+ return 0;
+}
+
+static int
+ax_pdu_add_varbindlist(struct ax *ax,
+ struct ax_varbind *vblist, size_t nvb)
+{
+ size_t i;
+ uint16_t temp;
+
+ for (i = 0; i < nvb; i++) {
+ temp = (uint16_t) vblist[i].avb_type;
+ if (ax_pdu_add_uint16(ax, temp) == -1 ||
+ ax_pdu_need(ax, 2))
+ return -1;
+ memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2);
+ ax->ax_wbtlen += 2;
+ if (ax_pdu_add_oid(ax, &(vblist[i].avb_oid), 0) == -1)
+ return -1;
+ switch (vblist[i].avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+ case AX_DATA_TYPE_COUNTER32:
+ case AX_DATA_TYPE_GAUGE32:
+ case AX_DATA_TYPE_TIMETICKS:
+ if (ax_pdu_add_uint32(ax,
+ vblist[i].avb_data.avb_uint32) == -1)
+ return -1;
+ break;
+ case AX_DATA_TYPE_COUNTER64:
+ if (ax_pdu_add_uint64(ax,
+ vblist[i].avb_data.avb_uint64) == -1)
+ return -1;
+ break;
+ case AX_DATA_TYPE_OCTETSTRING:
+ case AX_DATA_TYPE_IPADDRESS:
+ case AX_DATA_TYPE_OPAQUE:
+ if (ax_pdu_add_str(ax,
+ &(vblist[i].avb_data.avb_ostring)) == -1)
+ return -1;
+ break;
+ case AX_DATA_TYPE_OID:
+ if (ax_pdu_add_oid(ax,
+ &(vblist[i].avb_data.avb_oid), 1) == -1)
+ return -1;
+ break;
+ case AX_DATA_TYPE_NULL:
+ case AX_DATA_TYPE_NOSUCHOBJECT:
+ case AX_DATA_TYPE_NOSUCHINSTANCE:
+ case AX_DATA_TYPE_ENDOFMIBVIEW:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static uint16_t
+ax_pdutoh16(struct ax_pdu_header *header, uint8_t *buf)
+{
+ uint16_t value;
+
+ memcpy(&value, buf, sizeof(value));
+ if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
+ return be16toh(value);
+ return le16toh(value);
+}
+
+static uint32_t
+ax_pdutoh32(struct ax_pdu_header *header, uint8_t *buf)
+{
+ uint32_t value;
+
+ memcpy(&value, buf, sizeof(value));
+ if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
+ return be32toh(value);
+ return le32toh(value);
+}
+
+static uint64_t
+ax_pdutoh64(struct ax_pdu_header *header, uint8_t *buf)
+{
+ uint64_t value;
+
+ memcpy(&value, buf, sizeof(value));
+ if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
+ return be64toh(value);
+ return le64toh(value);
+}
+
+static ssize_t
+ax_pdutooid(struct ax_pdu_header *header, struct ax_oid *oid,
+ uint8_t *buf, size_t rawlen)
+{
+ size_t i = 0;
+ ssize_t nread;
+
+ if (rawlen < 4)
+ goto fail;
+ rawlen -= 4;
+ nread = 4;
+ oid->aoi_idlen = *buf++;
+ if (rawlen < (oid->aoi_idlen * 4))
+ goto fail;
+ nread += oid->aoi_idlen * 4;
+ if (*buf != 0) {
+ oid->aoi_id[0] = 1;
+ oid->aoi_id[1] = 3;
+ oid->aoi_id[2] = 6;
+ oid->aoi_id[3] = 1;
+ oid->aoi_id[4] = *buf;
+ oid->aoi_idlen += 5;
+ i = 5;
+ }
+ buf++;
+ oid->aoi_include = *buf;
+ for (buf += 2; i < oid->aoi_idlen; i++, buf += 4)
+ oid->aoi_id[i] = ax_pdutoh32(header, buf);
+
+ return nread;
+
+fail:
+ errno = EPROTO;
+ return -1;
+}
+
+static ssize_t
+ax_pdutoostring(struct ax_pdu_header *header,
+ struct ax_ostring *ostring, uint8_t *buf, size_t rawlen)
+{
+ ssize_t nread;
+
+ if (rawlen < 4)
+ goto fail;
+
+ ostring->aos_slen = ax_pdutoh32(header, buf);
+ rawlen -= 4;
+ buf += 4;
+ if (ostring->aos_slen > rawlen)
+ goto fail;
+ if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL)
+ return -1;
+ memcpy(ostring->aos_string, buf, ostring->aos_slen);
+ ostring->aos_string[ostring->aos_slen] = '\0';
+
+ nread = 4 + ostring->aos_slen;
+ if (ostring->aos_slen % 4 != 0)
+ nread += 4 - (ostring->aos_slen % 4);
+
+ return nread;
+
+fail:
+ errno = EPROTO;
+ return -1;
+}
+
+static ssize_t
+ax_pdutovarbind(struct ax_pdu_header *header,
+ struct ax_varbind *varbind, uint8_t *buf, size_t rawlen)
+{
+ ssize_t nread, rread = 4;
+
+ if (rawlen == 0)
+ return 0;
+
+ if (rawlen < 8)
+ goto fail;
+ varbind->avb_type = ax_pdutoh16(header, buf);
+
+ buf += 4;
+ rawlen -= 4;
+ nread = ax_pdutooid(header, &(varbind->avb_oid), buf, rawlen);
+ if (nread == -1)
+ return -1;
+ rread += nread;
+ buf += nread;
+ rawlen -= nread;
+
+ switch(varbind->avb_type) {
+ case AX_DATA_TYPE_INTEGER:
+ case AX_DATA_TYPE_COUNTER32:
+ case AX_DATA_TYPE_GAUGE32:
+ case AX_DATA_TYPE_TIMETICKS:
+ if (rawlen < 4)
+ goto fail;
+ varbind->avb_data.avb_uint32 = ax_pdutoh32(header, buf);
+ return rread + 4;
+ case AX_DATA_TYPE_COUNTER64:
+ if (rawlen < 8)
+ goto fail;
+ varbind->avb_data.avb_uint64 = ax_pdutoh64(header, buf);
+ return rread + 8;
+ case AX_DATA_TYPE_OCTETSTRING:
+ case AX_DATA_TYPE_IPADDRESS:
+ case AX_DATA_TYPE_OPAQUE:
+ nread = ax_pdutoostring(header,
+ &(varbind->avb_data.avb_ostring), buf, rawlen);
+ if (nread == -1)
+ return -1;
+ return nread + rread;
+ case AX_DATA_TYPE_OID:
+ nread = ax_pdutooid(header, &(varbind->avb_data.avb_oid),
+ buf, rawlen);
+ if (nread == -1)
+ return -1;
+ return nread + rread;
+ case AX_DATA_TYPE_NULL:
+ case AX_DATA_TYPE_NOSUCHOBJECT:
+ case AX_DATA_TYPE_NOSUCHINSTANCE:
+ case AX_DATA_TYPE_ENDOFMIBVIEW:
+ return rread;
+ }
+
+fail:
+ errno = EPROTO;
+ return -1;
+}
diff --git a/lib/libagentx/ax.h b/lib/libagentx/ax.h
new file mode 100644
index 00000000000..863507bc0b6
--- /dev/null
+++ b/lib/libagentx/ax.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#define AX_PDU_FLAG_INSTANCE_REGISTRATION (1 << 0)
+#define AX_PDU_FLAG_NEW_INDEX (1 << 1)
+#define AX_PDU_FLAG_ANY_INDEX (1 << 2)
+#define AX_PDU_FLAG_NON_DEFAULT_CONTEXT (1 << 3)
+#define AX_PDU_FLAG_NETWORK_BYTE_ORDER (1 << 4)
+
+#define AX_PRIORITY_DEFAULT 127
+
+enum ax_byte_order {
+ AX_BYTE_ORDER_BE,
+ AX_BYTE_ORDER_LE
+};
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define AX_BYTE_ORDER_NATIVE AX_BYTE_ORDER_BE
+#else
+#define AX_BYTE_ORDER_NATIVE AX_BYTE_ORDER_LE
+#endif
+
+enum ax_pdu_type {
+ AX_PDU_TYPE_OPEN = 1,
+ AX_PDU_TYPE_CLOSE = 2,
+ AX_PDU_TYPE_REGISTER = 3,
+ AX_PDU_TYPE_UNREGISTER = 4,
+ AX_PDU_TYPE_GET = 5,
+ AX_PDU_TYPE_GETNEXT = 6,
+ AX_PDU_TYPE_GETBULK = 7,
+ AX_PDU_TYPE_TESTSET = 8,
+ AX_PDU_TYPE_COMMITSET = 9,
+ AX_PDU_TYPE_UNDOSET = 10,
+ AX_PDU_TYPE_CLEANUPSET = 11,
+ AX_PDU_TYPE_NOTIFY = 12,
+ AX_PDU_TYPE_PING = 13,
+ AX_PDU_TYPE_INDEXALLOCATE = 14,
+ AX_PDU_TYPE_INDEXDEALLOCATE = 15,
+ AX_PDU_TYPE_ADDAGENTCAPS = 16,
+ AX_PDU_TYPE_REMOVEAGENTCAPS = 17,
+ AX_PDU_TYPE_RESPONSE = 18
+};
+
+enum ax_pdu_error {
+ AX_PDU_ERROR_NOERROR = 0,
+ AX_PDU_ERROR_GENERR = 5,
+ AX_PDU_ERROR_NOACCESS = 6,
+ AX_PDU_ERROR_WRONGTYPE = 7,
+ AX_PDU_ERROR_WRONGLENGTH = 8,
+ AX_PDU_ERROR_WRONGENCODING = 9,
+ AX_PDU_ERROR_WRONGVALUE = 10,
+ AX_PDU_ERROR_NOCREATION = 11,
+ AX_PDU_ERROR_INCONSISTENTVALUE = 12,
+ AX_PDU_ERROR_RESOURCEUNAVAILABLE = 13,
+ AX_PDU_ERROR_COMMITFAILED = 14,
+ AX_PDU_ERROR_UNDOFAILED = 15,
+ AX_PDU_ERROR_NOTWRITABLE = 17,
+ AX_PDU_ERROR_INCONSISTENTNAME = 18,
+ AX_PDU_ERROR_OPENFAILED = 256,
+ AX_PDU_ERROR_NOTOPEN = 257,
+ AX_PDU_ERROR_INDEXWRONGTYPE = 258,
+ AX_PDU_ERROR_INDEXALREADYALLOCATED = 259,
+ AX_PDU_ERROR_INDEXNONEAVAILABLE = 260,
+ AX_PDU_ERROR_INDEXNOTALLOCATED = 261,
+ AX_PDU_ERROR_UNSUPPORTEDCONETXT = 262,
+ AX_PDU_ERROR_DUPLICATEREGISTRATION = 263,
+ AX_PDU_ERROR_UNKNOWNREGISTRATION = 264,
+ AX_PDU_ERROR_UNKNOWNAGENTCAPS = 265,
+ AX_PDU_ERROR_PARSEERROR = 266,
+ AX_PDU_ERROR_REQUESTDENIED = 267,
+ AX_PDU_ERROR_PROCESSINGERROR = 268
+};
+
+enum ax_data_type {
+ AX_DATA_TYPE_INTEGER = 2,
+ AX_DATA_TYPE_OCTETSTRING = 4,
+ AX_DATA_TYPE_NULL = 5,
+ AX_DATA_TYPE_OID = 6,
+ AX_DATA_TYPE_IPADDRESS = 64,
+ AX_DATA_TYPE_COUNTER32 = 65,
+ AX_DATA_TYPE_GAUGE32 = 66,
+ AX_DATA_TYPE_TIMETICKS = 67,
+ AX_DATA_TYPE_OPAQUE = 68,
+ AX_DATA_TYPE_COUNTER64 = 70,
+ AX_DATA_TYPE_NOSUCHOBJECT = 128,
+ AX_DATA_TYPE_NOSUCHINSTANCE = 129,
+ AX_DATA_TYPE_ENDOFMIBVIEW = 130
+};
+
+enum ax_close_reason {
+ AX_CLOSE_OTHER = 1,
+ AX_CLOSEN_PARSEERROR = 2,
+ AX_CLOSE_PROTOCOLERROR = 3,
+ AX_CLOSE_TIMEOUTS = 4,
+ AX_CLOSE_SHUTDOWN = 5,
+ AX_CLOSE_BYMANAGER = 6
+};
+
+struct ax {
+ int ax_fd;
+ enum ax_byte_order ax_byteorder;
+ uint8_t *ax_rbuf;
+ size_t ax_rblen;
+ size_t ax_rbsize;
+ uint8_t *ax_wbuf;
+ size_t ax_wblen;
+ size_t ax_wbtlen;
+ size_t ax_wbsize;
+ uint32_t *ax_packetids;
+ size_t ax_packetidsize;
+};
+
+#ifndef AX_PRIMITIVE
+#define AX_PRIMITIVE
+
+#define AX_OID_MAX_LEN 128
+
+struct ax_oid {
+ uint8_t aoi_include;
+ uint32_t aoi_id[AX_OID_MAX_LEN];
+ size_t aoi_idlen;
+};
+
+struct ax_ostring {
+ unsigned char *aos_string;
+ uint32_t aos_slen;
+};
+#endif
+
+struct ax_searchrange {
+ struct ax_oid asr_start;
+ struct ax_oid asr_stop;
+};
+
+struct ax_pdu_header {
+ uint8_t aph_version;
+ uint8_t aph_type;
+ uint8_t aph_flags;
+ uint8_t aph_reserved;
+ uint32_t aph_sessionid;
+ uint32_t aph_transactionid;
+ uint32_t aph_packetid;
+ uint32_t aph_plength;
+};
+
+struct ax_varbind {
+ enum ax_data_type avb_type;
+ struct ax_oid avb_oid;
+ union ax_data {
+ uint32_t avb_uint32;
+ uint64_t avb_uint64;
+ struct ax_ostring avb_ostring;
+ struct ax_oid avb_oid;
+ } avb_data;
+};
+
+struct ax_pdu {
+ struct ax_pdu_header ap_header;
+ struct ax_ostring ap_context;
+ union {
+ struct ax_pdu_searchrangelist {
+ size_t ap_nsr;
+ struct ax_searchrange *ap_sr;
+ } ap_srl;
+ struct ax_pdu_getbulk {
+ uint16_t ap_nonrep;
+ uint16_t ap_maxrep;
+ struct ax_pdu_searchrangelist ap_srl;
+ } ap_getbulk;
+ struct ax_pdu_varbindlist {
+ struct ax_varbind *ap_varbind;
+ size_t ap_nvarbind;
+ } ap_vbl;
+ struct ax_pdu_response {
+ uint32_t ap_uptime;
+ enum ax_pdu_error ap_error;
+ uint16_t ap_index;
+ struct ax_varbind *ap_varbindlist;
+ size_t ap_nvarbind;
+ } ap_response;
+ void *ap_raw;
+ } ap_payload;
+};
+
+struct ax *ax_new(int);
+void ax_free(struct ax *);
+struct ax_pdu *ax_recv(struct ax *);
+ssize_t ax_send(struct ax *);
+uint32_t ax_open(struct ax *, uint8_t, struct ax_oid *,
+ struct ax_ostring *);
+uint32_t ax_close(struct ax *, uint32_t, enum ax_close_reason);
+uint32_t ax_indexallocate(struct ax *, uint8_t, uint32_t,
+ struct ax_ostring *, struct ax_varbind *, size_t);
+uint32_t ax_indexdeallocate(struct ax *, uint32_t,
+ struct ax_ostring *, struct ax_varbind *, size_t);
+uint32_t ax_addagentcaps(struct ax *, uint32_t, struct ax_ostring *,
+ struct ax_oid *, struct ax_ostring *);
+uint32_t ax_removeagentcaps(struct ax *, uint32_t,
+ struct ax_ostring *, struct ax_oid *);
+uint32_t ax_register(struct ax *, uint8_t, uint32_t,
+ struct ax_ostring *, uint8_t, uint8_t, uint8_t, struct ax_oid *,
+ uint32_t);
+uint32_t ax_unregister(struct ax *, uint32_t, struct ax_ostring *,
+ uint8_t, uint8_t, struct ax_oid *, uint32_t);
+int ax_response(struct ax *, uint32_t, uint32_t, uint32_t,
+ struct ax_ostring *, uint32_t, uint16_t, uint16_t,
+ struct ax_varbind *, size_t);
+void ax_pdu_free(struct ax_pdu *);
+void ax_varbind_free(struct ax_varbind *);
+const char *ax_error2string(enum ax_pdu_error);
+const char *ax_pdutype2string(enum ax_pdu_type);
+const char *ax_oid2string(struct ax_oid *);
+const char *ax_oidrange2string(struct ax_oid *, uint8_t, uint32_t);
+const char *ax_varbind2string(struct ax_varbind *);
+const char *ax_closereason2string(enum ax_close_reason);
+int ax_oid_cmp(struct ax_oid *, struct ax_oid *);
+int ax_oid_add(struct ax_oid *, uint32_t);
diff --git a/lib/libagentx/shlib_version b/lib/libagentx/shlib_version
index 97c9f92d6b8..1edea46de91 100644
--- a/lib/libagentx/shlib_version
+++ b/lib/libagentx/shlib_version
@@ -1,2 +1,2 @@
-major=0
+major=1
minor=0
diff --git a/lib/libagentx/subagentx.3 b/lib/libagentx/subagentx.3
deleted file mode 100644
index d283ff198e8..00000000000
--- a/lib/libagentx/subagentx.3
+++ /dev/null
@@ -1,645 +0,0 @@
-.\" $OpenBSD: subagentx.3,v 1.4 2020/10/18 06:26:17 bentley Exp $
-.\"
-.\" Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.Dd $Mdocdate: October 18 2020 $
-.Dt SUBAGENTX 3
-.Os
-.Sh NAME
-.Nm subagentx_log_fatal ,
-.Nm subagentx_log_warn ,
-.Nm subagentx_log_info ,
-.Nm subagentx_log_debug ,
-.Nm subagentx ,
-.Nm subagentx_connect ,
-.Nm subagentx_read ,
-.Nm subagentx_write ,
-.Nm subagentx_wantwrite ,
-.Nm subagentx_free ,
-.Nm subagentx_session ,
-.Nm subagentx_session_free ,
-.Nm subagentx_context ,
-.Nm subagentx_context_object_find ,
-.Nm subagentx_context_object_nfind ,
-.Nm subagentx_context_uptime ,
-.Nm subagentx_context_free ,
-.Nm subagentx_region ,
-.Nm subagentx_region_free ,
-.Nm subagentx_agentcaps ,
-.Nm subagentx_agentcaps_free ,
-.Nm subagentx_index_integer_new ,
-.Nm subagentx_index_integer_any ,
-.Nm subagentx_index_integer_value ,
-.Nm subagentx_index_integer_dynamic ,
-.Nm subagentx_index_string_dynamic ,
-.Nm subagentx_index_nstring_dynamic ,
-.Nm subagentx_index_oid_dynamic ,
-.Nm subagentx_index_noid_dynamic ,
-.Nm subagentx_index_ipaddress_dynamic ,
-.Nm subagentx_index_free ,
-.Nm subagentx_object ,
-.Nm subagentx_object_free ,
-.Nm subagentx_varbind_integer ,
-.Nm subagentx_varbind_string ,
-.Nm subagentx_varbind_nstring ,
-.Nm subagentx_varbind_printf ,
-.Nm subagentx_varbind_null ,
-.Nm subagentx_varbind_oid ,
-.Nm subagentx_varbind_object ,
-.Nm subagentx_varbind_index ,
-.Nm subagentx_varbind_ipaddress ,
-.Nm subagentx_varbind_counter32 ,
-.Nm subagentx_varbind_gauge32 ,
-.Nm subagentx_varbind_timeticks ,
-.Nm subagentx_varbind_opaque ,
-.Nm subagentx_varbind_counter64 ,
-.Nm subagentx_varbind_notfound ,
-.Nm subagentx_varbind_error ,
-.Nm subagentx_varbind_request ,
-.Nm subagentx_varbind_get_index_integer ,
-.Nm subagentx_varbind_get_index_string ,
-.Nm subagentx_varbind_get_index_oid ,
-.Nm subagentx_varbind_get_index_ipaddress ,
-.Nm subagentx_varbind_set_index_integer ,
-.Nm subagentx_varbind_set_index_string ,
-.Nm subagentx_varbind_set_index_nstring ,
-.Nm subagentx_varbind_set_index_oid ,
-.Nm subagentx_varbind_set_index_object ,
-.Nm subagentx_varbind_set_index_ipaddress
-.Nd manage an interface to an agentx master
-.Sh SYNOPSIS
-.In subagentx.h
-.Ft extern void
-.Fn (*subagentx_log_fatal) "const char *fmt" ...
-.Ft extern void
-.Fn (*subagentx_log_warn) "const char *fmt" ...
-.Ft extern void
-.Fn (*subagentx_log_info) "const char *fmt" ...
-.Ft extern void
-.Fn (*subagentx_log_debug) "const char *fmt" ...
-.Ft struct subagentx *
-.Fn subagentx "void (*nofd)(struct subagentx *, void *, int)" "void *cookie"
-.Ft void
-.Fn subagentx_connect "struct subagentx *sa" "int fd"
-.Ft void
-.Fn subagentx_read "struct subagentx *sa"
-.Ft void
-.Fn subagentx_write "struct subagentx *sa"
-.Ft extern void
-.Fn (*subagentx_wantwrite) "struct subagentx *sa" "int fd"
-.Ft void
-.Fn subagentx_free "struct subagentx *sa"
-.Ft struct subagentx_session *
-.Fo subagentx_session
-.Fa "struct subagentx *sa" "uint32_t oid[]" "size_t oidlen"
-.Fa "const char *descr" "uint8_t timeout"
-.Fc
-.Ft void
-.Fn subagentx_session_free "struct subagentx_session *sas"
-.Ft struct subagentx_context *
-.Fn subagentx_context "struct subagentx_session *sas" "const char *name"
-.Ft struct subagentx_object *
-.Fo subagentx_context_object_find
-.Fa "struct subagentx_context *sac" "const uint32_t oid[]" "size_t oidlen"
-.Fa "int active" "int instance"
-.Fc
-.Ft struct subagentx_object *
-.Fo subagentx_context_object_nfind
-.Fa "struct subagentx_context *" "const uint32_t oid[]" "size_t oidlen"
-.Fa "int active" "int inclusive"
-.Fc
-.Ft uint32_t
-.Fn subagentx_context_uptime "struct subagentx_context *sac"
-.Ft void
-.Fn subagentx_context_free "struct subagentx_context *sac"
-.Ft struct subagentx_agentcaps *
-.Fo subagentx_agentcaps
-.Fa "struct subagentx_context *sac" "uint32_t oid[]" "size_t oidlen"
-.Fa "const char *descr"
-.Fc
-.Ft void
-.Fn subagentx_agentcaps_free "struct subagentx_agentcaps *saa"
-.Ft struct subagentx_region *
-.Fo subagentx_region
-.Fa "struct subagentx_context *sac" "uint32_t oid[]"
-.Fa "size_t oidlen" "uint8_t timeout"
-.Fc
-.Ft void
-.Fn subagentx_region_free "struct subagentx_region *sar"
-.Ft struct subagentx_index *
-.Fo subagentx_index_integer_new
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_integer_any
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_integer_value
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fa "uint32_t value"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_integer_dynamic
-.Fa "struct subagentx_region *sar" "uint32_t oid[] "size_t oidlen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_string_dynamic
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_nstring_dynamic
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fa "size_t slen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_oid_dynamic
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_noid_dynamic
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fa "size_t vlen"
-.Fc
-.Ft struct subagentx_index *
-.Fo subagentx_index_ipaddress_dynamic
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fc
-.Ft void
-.Fn subagentx_index_free "struct subagentx_index *sai"
-.Ft struct subagentx_object *
-.Fo subagentx_object
-.Fa "struct subagentx_region *sar" "uint32_t oid[]" "size_t oidlen"
-.Fa "struct subagentx_index *index[]" "size_t indexlen" "int implied"
-.Fa "void (*getcb)(struct subagentx_varbind *)"
-.Fc
-.Ft void
-.Fn subagentx_object_free "struct subagentx_object *sao"
-.Ft void
-.Fn subagentx_varbind_integer "struct subagentx_varbind *sav" "uint32_t value"
-.Ft void
-.Fn subagentx_varbind_string "struct subagentx_varbind *sav" "const char *value"
-.Ft void
-.Fo subagentx_varbind_nstring
-.Fa "struct subagentx_varbind *sav" "const char *value" "size_t slen"
-.Fc
-.Ft void
-.Fo subagentx_varbind_printf
-.Fa "struct subagentx_varbind *sav" "const char *fmt" ...
-.Fc
-.Ft void
-.Fn subagentx_varbind_null "struct subagentx_varbind *sav"
-.Ft void
-.Fo subagentx_varbind_oid
-.Fa "struct subagentx_varbind *sav" "const uint32_t oid[]" "size_t oidlen"
-.Fc
-.Ft void
-.Fo subagentx_varbind_object
-.Fa "struct subagentx_varbind *sav" "struct subagentx_object *sao"
-.Fc
-.Ft void
-.Fo subagentx_varbind_index
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fc
-.Ft void
-.Fo subagentx_varbind_ipaddress
-.Fa "struct subagentx_varbind *sav" "const struct in_addr *addr"
-.Fc
-.Ft void
-.Fn subagentx_varbind_counter32 "struct subagentx_varbind *sav" "uint32_t value"
-.Ft void
-.Fn subagentx_varbind_gauge32 "struct subagentx_varbind *sav" "uint32_t value"
-.Ft void
-.Fo subagentx_varbind_timeticks
-.Fa "struct subagentx_varbind *sav" "uint32_t value"
-.Fc
-.Ft void
-.Fo subagentx_varbind_opaque
-.Fa "struct subagentx_varbind *sav" "const char *value" "size_t slen"
-.Fc
-.Ft void
-.Fn subagentx_varbind_counter64 "struct subagentx_varbind *sav" "uint64_t value"
-.Ft void
-.Fn subagentx_varbind_notfound "struct subagentx_varbind *sav"
-.Ft void
-.Fn subagentx_varbind_error "struct subagentx_varbind *sav"
-.Ft enum subagentx_request_type
-.Fn subagentx_varbind_request "struct subagentx_varbind *sav"
-.Ft uint32_t
-.Fo subagentx_varbind_get_index_integer
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fc
-.Ft const unsigned char *
-.Fo subagentx_varbind_get_index_string
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai" "size_t *slen"
-.Fa "int *implied"
-.Fc
-.Ft const uint32_t *
-.Fo subagentx_varbind_get_index_oid
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "size_t *oidlen" "int *implied"
-.Fc
-.Ft const struct in_addr *
-.Fo subagentx_varbind_get_index_ipaddress
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fc
-.Ft void
-.Fo subagentx_varbind_set_index_integer
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "uint32_t value"
-.Fc
-.Ft void
-.Fo subagentx_varbind_set_index_string
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "const unsigned char *value"
-.Fc
-.Ft void
-.Fo subagentx_varbind_set_index_nstring
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "const unsigned char *value" "size_t slen"
-.Fc
-.Ft void
-.Fo subagentx_varbind_set_index_oid
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "const uint32_t *oid" "size_t oidlen"
-.Fc
-.Ft void
-.Fo subagentx_varbind_set_index_object
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "struct subagentx_object *sao"
-.Fc
-.Ft void
-.Fo subagentx_varbind_set_index_ipaddress
-.Fa "struct subagentx_varbind *sav" "struct subagentx_index *sai"
-.Fa "const struct in_addr *addr"
-.Fc
-.Bd -literal
-enum subagentx_request_type {
- SUBAGENTX_REQUEST_TYPE_GET,
- SUBAGENTX_REQUEST_TYPE_GETNEXT,
- SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
-};
-.Ed
-.Fd #define SUBAGENTX_AGENTX_MASTER \(dq/var/agentx/master\(dq
-.Fd #define SUBAGENTX_OID_MAX_LEN 128
-.Fd #define SUBAGENTX_OID_INDEX_MAX_LEN 10
-.Fd #define SUBAGENTX_OID(...)
-.Fd #define SUBAGENTX_MIB2 1, 3, 6, 1, 2, 1
-.Fd #define SUBAGENTX_ENTERPRISES 1, 3, 6, 1, 4, 1
-.Sh DESCRIPTION
-The
-.Nm subagentx
-functions allow an application to describe their MIB layout and provide an
-.Fa fd
-based interface to control the internal agentx state.
-.Nm subagentx
-is not thread safe.
-.Ss DESCRIBING THE MIB
-.Nm subagentx
-is a framework to abstract away the agentx protocol from the application.
-For the framework to report information to the administrator, the
-.Fn subagentx_log_fatal ,
-.Fn subagentx_log_warn ,
-.Fn subagentx_log_info
-and
-.Fn subagentx_log_debug
-functions must be set.
-.Pp
-When
-.Fa sa
-is created by
-.Fn subagentx
-or when
-.Fa sa
-detects that there is no connection to the agentx master it calls out to
-.Fa nofd
-with itself,
-.Fa cookie
-and an integer
-.Fa close
-as arguments.
-If
-.Fa close
-is not set
-.Fn nofd
-is expected to set up a new
-.Fa fd
-to the agentx master.
-This one can usually be found at
-.Dv SUBAGENTX_AGENTX_MASTER .
-This
-.Fa fd
-can be returned to
-.Fa sa
-at any moment via
-.Fn subagentx_connect ,
-but must always be done as a result of a call to
-.Fn nofd .
-Once
-.Fn subagentx_connect
-has been called the application is responsible for retrieving data when available
-on
-.Fa fd
-by calling
-.Fn subagentx_read .
-If nonblocking writes are desirable the
-.Fn subagentx_wantwrite
-pointer can be set to an application function and will be called as soon as
-there's data available to be written out.
-Once
-.Fa fd
-is ready for write the function
-.Fn subagentx_write
-should be called.
-.Pp
-.Fa sa
-can be freed via
-.Fn subagentx_free .
-It will close all active sessions and free all derived objects.
-Once freed no new objects can be derived from the freed objects.
-Once all sessions are closed it will call out to
-.Fn nofd
-with
-.Fa close
-set, indicating that the application can clean up any context related to
-.Fa sa .
-.Pp
-On top of the
-.Fa sa
-connection a
-.Vt subagentx_session
-must be set up.
-Normally there's only a single session per
-.Fa sa .
-The
-.Fa timeout
-argument specifies the maximum time in seconds the master should wait for a
-reply before determining we're gone.
-If set to 0 the agentx master determines the timeout.
-The
-.Fa oid
-and
-.Fa oidlen
-combination identifies the subagent and will be visible through the
-agentxSessionObjectID object on the agentx master.
-The
-.Fa descr
-is a short displaystring description of the agent and will be visiable through
-the agentxSessionDescr object on the agentx master.
-.Pp
-The
-.Vt subagentx_context
-is the SNMPv3 context in which the objects operate and is built on top of
-subagentx_session
-.Fa sas .
-If the default context is requested
-.Fa name
-must be NULL.
-.Pp
-.Fn subagentx_agentcaps
-registers an entry in the agentx master's sysORTable.
-The
-.Fa oid ,
-.Fa oidlen
-combination should point to an AGENT-CAPABILITIES object which describes the
-capabilities of the subagent.
-.Fa descr
-should be a textual description of the capabilities.
-If no AGENT-CAPABILITIES object is defined this function can be omitted.
-.Pp
-A
-.Vt subagentx_region
-indicates a region inside the object-tree for which get- and set-requests will
-be queried.
-If the OID has already been claimed by another subagent it will try to claim it
-on a lower priority.
-The
-.Fa timeout
-parameter overrules its
-.Vt subagentx_session
-counterpart.
-.Pp
-For objects in a table one or more
-.Ft subagentx_index
-elements must be supplied.
-.Fn subagentx_index_integer_new ,
-.Fn subagentx_index_integer_any
-and
-.Fn subagentx_index_integer_value
-register an integer index at the agentx master.
-Of these
-.Fn subagentx_index_integer_new
-registers a new, previously unused, index;
-.Fn subagentx_index_integer_any
-registers the first available index;
-and
-.Fn subagentx_index_integer_value
-tries to register a specific value.
-If the registration of an index fails an error will be logged and all objects
-using it will remain disabled.
-The OID where the index should be registered is documented by the MIB.
-These registered indices are usually used for tables where multiple subagents
-are registered.
-.Pp
-For dynamic indices the subagentx_index_*_dynamic functions can be used, based
-on the data type of the object.
-The data type should match the data type in the MIB at the
-.Fa oid
-object.
-Indices of data type string or oid with a fixed length should be created via
-.Fn subagentx_index_nstring_dynamic
-and
-.Fn subagentx_index_noid_dynamic
-respectively.
-.Pp
-.Vt subagentx_object
-is an object as described in the MIB.
-For scalar objects
-.Pq without indices
-the final zero must be omitted.
-For table entries a list of 1 or more indices must be added via
-.Fa index
-and
-.Fa indexlen .
-The list of indices must match the INDEX list on the ENTRY object in the MIB.
-The total length of the OID, including indices, can't be more than
-.Dv SUBAGENTX_OID_MAX_LEN
-and indexlen can't be more than
-.Dv SUBAGENTX_OID_INDEX_MAX_LEN .
-If
-.Fa implied
-is set the final index must be of type OID or string and will omit the leading
-length indicator.
-This value must only be set if specified in the MIB.
-.Fn getcb
-will be called for each varbind in a GET, GETNEXT or GETBULK request that
-matches the object.
-.Ss HANDLING GET REQUESTS
-A call to
-.Fn getcb
-must eventually result in a call to one of the following functions:
-.Bl -tag -width subagentx_varbind_counter32()
-.It Fn subagentx_varbind_integer
-Set the return value to an uint32_t value.
-.It Fn subagentx_varbind_string
-A C string wrapper around
-.Fn subagentx_varbind_nstring .
-.It Fn subagentx_varbind_nstring
-Set the return value to an octetstring.
-.It Fn subagentx_varbind_printf
-A printf wrapper around
-.Fn subagentx_varbind_nstring .
-.It Fn subagentx_varbind_null
-Set the return value to null.
-.It Fn subagentx_varbind_oid
-Set the return value to an OID value.
-.It Fn subagentx_varbind_object
-An subagentx_object wrapper around
-.Fn subagentx_varbind_oid .
-.It Fn subagentx_varbind_index
-An subagentx_index wrapper around
-.Fn subagentx_varbind_oid .
-.It Fn subagentx_varbind_ipaddress
-Set the return value to ipaddress.
-.It Fn subagentx_varbind_counter32
-Set the return value to an uint32_t of type counter32.
-.It Fn subagentx_varbind_gauge32
-Set the return value to an uint32_t of type gauge32.
-.It Fn subagentx_varbind_timeticks
-Set the return value to an uint32_t of type timeticks.
-.It Fn subagentx_varbind_opaque
-Set the return value to an opaque value.
-.It Fn subagentx_varbind_counter64
-Set the return value to an uint64_t of type counter64.
-.It Fn subagentx_varbind_notfound
-When the request is of type GET return an nosuchinstance error.
-When the request is of type GETNEXT or GETBULK return an endofmibview error.
-On endofmibview the next object is queried.
-This function can only be called on objects that contain one or more *_dynamic
-indices.
-.It Fn subagentx_varbind_error
-Returns a GENERR error to the client.
-.El
-.Pp
-For objects containing *_dynamic indices the following support functions are to
-be used:
-.Bl -tag -width Ds
-.It Fn subagentx_varbind_request
-Returns whether the request is of type GET, GETNEXT or GETNEXTINCLUSIVE.
-.It Fn subagentx_varbind_get_index_integer
-Retrieve a single uint32_t index value.
-.It Fn subagentx_varbind_get_index_string
-Retrieve an octetstring index value.
-.Fa slen
-is the length of the string and
-.Fa implied
-indicates if the next value for this index should be length sorted before
-alphabetically sorted.
-.It Fn subagentx_varbind_get_index_oid
-Retrieve an oid index value.
-.Fa oidlen
-is the length of the oid and
-.Fa implied
-indicates if the next value for this index should be length sorted before
-alphabetically sorted.
-.It Fn subagentx_varbind_get_index_ipaddress
-Retrieve an ipaddress index value.
-.It Fn subagentx_varbind_set_index_integer
-Sets a single uint32_t index value.
-.It Fn subagentx_varbind_set_index_string
-A C string wrapper around
-.Fn subagentx_varbind_set_index_nstring .
-.It Fn subagentx_varbind_set_index_nstring
-Set an octetstring index value.
-.It Fn subagentx_varbind_set_index_oid
-Set an oid index value.
-.It Fn subagentx_varbind_set_index_object
-A subagentx_object wrapper around
-.Fn subagentx_varbind_set_index_oid .
-.It Fn subagentx_varbind_set_index_ipaddress
-Set an ipaddress index value.
-.El
-.Pp
-For these functions
-.Fa sai
-must be part of the object the request is performed on.
-The function type must also match the data type of
-.Fa sai .
-.Pp
-Other functions that can retrieve information from the agentx context are:
-.Bl -tag -width Ds
-.It Fn subagentx_context_object_find
-Find a subagentx_object created inside subagentx_context
-.Fa sac
-based on
-.Fa oid
-and
-.Fa oidlen .
-If
-.Fa active
-is set the object must be reachable from the agentx master, else NULL is
-returned.
-If
-.Fa oid
-can be an instance, find its parent object.
-.It Fn subagentx_context_object_nfind
-Find the next subagentx_object created inside subagentx_context
-.Fa sac
-based on
-.Fa oid
-and
-.Fa oidlen .
-If
-.Fa active
-is set the object must be reachable from the agentx master, else NULL is
-returned.
-If
-.Fa inclusive
-is set the object returned may also exactly match
-.Fa oid .
-.It Fn subagentx_context_uptime
-Returns the sysuptime in seconds for
-.Fa sac
-in timeticks.
-.El
-.Sh SEE ALSO
-.Xr snmp 1 ,
-.Xr snmpd 8
-.Sh STANDARDS
-.Rs
-.%A M. Daniele
-.%A B. Wijnen
-.%A M. Ellison, Ed.
-.%A D. Francisco, Ed.
-.%D January 2000
-.%R RFC 2741
-.%T Agent Extensibility (AgentX) Protocol Version 1
-.Re
-.Pp
-.Rs
-.%A L. Heintz
-.%A S. Gudur
-.%A M. Ellison, Ed.
-.%D January 2000
-.%R RFC 2742
-.%T Definitions of Managed Objects for Extensible SNMP Agents
-.Re
-.Sh HISTORY
-The
-.Nm subagentx
-API first appeared in
-.Ox 6.8 .
-.Sh AUTHORS
-.An Martijn van Duren Aq Mt martijn@openbsd.org
diff --git a/lib/libagentx/subagentx.c b/lib/libagentx/subagentx.c
deleted file mode 100644
index 4d34b28304d..00000000000
--- a/lib/libagentx/subagentx.c
+++ /dev/null
@@ -1,4003 +0,0 @@
-/*
- * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <netinet/in.h>
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "subagentx_internal.h"
-#include "subagentx.h"
-
-enum subagentx_index_type {
- SAI_TYPE_NEW,
- SAI_TYPE_ANY,
- SAI_TYPE_VALUE,
- SAI_TYPE_DYNAMIC
-};
-
-#define SUBAGENTX_CONTEXT_CTX(sac) (sac->sac_name_default ? NULL : \
- &(sac->sac_name))
-
-struct subagentx_agentcaps {
- struct subagentx_context *saa_sac;
- struct agentx_oid saa_oid;
- struct agentx_ostring saa_descr;
- enum subagentx_cstate saa_cstate;
- enum subagentx_dstate saa_dstate;
- TAILQ_ENTRY(subagentx_agentcaps) saa_sac_agentcaps;
-};
-
-struct subagentx_region {
- struct subagentx_context *sar_sac;
- struct agentx_oid sar_oid;
- uint8_t sar_timeout;
- uint8_t sar_priority;
- enum subagentx_cstate sar_cstate;
- enum subagentx_dstate sar_dstate;
- TAILQ_HEAD(, subagentx_index) sar_indices;
- TAILQ_HEAD(, subagentx_object) sar_objects;
- TAILQ_ENTRY(subagentx_region) sar_sac_regions;
-};
-
-struct subagentx_index {
- struct subagentx_region *sai_sar;
- enum subagentx_index_type sai_type;
- struct agentx_varbind sai_vb;
- struct subagentx_object **sai_object;
- size_t sai_objectlen;
- size_t sai_objectsize;
- enum subagentx_cstate sai_cstate;
- enum subagentx_dstate sai_dstate;
- TAILQ_ENTRY(subagentx_index) sai_sar_indices;
-};
-
-struct subagentx_object {
- struct subagentx_region *sao_sar;
- struct agentx_oid sao_oid;
- struct subagentx_index *sao_index[SUBAGENTX_OID_INDEX_MAX_LEN];
- size_t sao_indexlen;
- int sao_implied;
- uint8_t sao_timeout;
- /* Prevent freeing object while in use by get and set requesets */
- uint32_t sao_lock;
- void (*sao_get)(struct subagentx_varbind *);
- enum subagentx_cstate sao_cstate;
- enum subagentx_dstate sao_dstate;
- RB_ENTRY(subagentx_object) sao_sac_objects;
- TAILQ_ENTRY(subagentx_object) sao_sar_objects;
-};
-
-struct subagentx_varbind {
- struct subagentx_get *sav_sag;
- struct subagentx_object *sav_sao;
- struct subagentx_varbind_index {
- struct subagentx_index *sav_sai;
- union agentx_data sav_idata;
- uint8_t sav_idatacomplete;
- } sav_index[SUBAGENTX_OID_INDEX_MAX_LEN];
- size_t sav_indexlen;
- int sav_initialized;
- int sav_include;
- struct agentx_varbind sav_vb;
- struct agentx_oid sav_start;
- struct agentx_oid sav_end;
- enum agentx_pdu_error sav_error;
-};
-
-#define SUBAGENTX_GET_CTX(sag) (sag->sag_context_default ? NULL : \
- &(sag->sag_context))
-struct subagentx_request {
- uint32_t sar_packetid;
- int (*sar_cb)(struct agentx_pdu *, void *);
- void *sar_cookie;
- RB_ENTRY(subagentx_request) sar_sa_requests;
-};
-
-static void subagentx_start(struct subagentx *);
-static void subagentx_finalize(struct subagentx *, int);
-static void subagentx_wantwritenow(struct subagentx *, int);
-void (*subagentx_wantwrite)(struct subagentx *, int) =
- subagentx_wantwritenow;
-static void subagentx_reset(struct subagentx *);
-static void subagentx_free_finalize(struct subagentx *);
-static int subagentx_session_start(struct subagentx_session *);
-static int subagentx_session_finalize(struct agentx_pdu *, void *);
-static int subagentx_session_close(struct subagentx_session *,
- enum agentx_close_reason);
-static int subagentx_session_close_finalize(struct agentx_pdu *, void *);
-static void subagentx_session_free_finalize(struct subagentx_session *);
-static void subagentx_session_reset(struct subagentx_session *);
-static void subagentx_context_start(struct subagentx_context *);
-static void subagentx_context_free_finalize(struct subagentx_context *);
-static void subagentx_context_reset(struct subagentx_context *);
-static int subagentx_agentcaps_start(struct subagentx_agentcaps *);
-static int subagentx_agentcaps_finalize(struct agentx_pdu *, void *);
-static int subagentx_agentcaps_close(struct subagentx_agentcaps *);
-static int subagentx_agentcaps_close_finalize(struct agentx_pdu *, void *);
-static void subagentx_agentcaps_free_finalize(struct subagentx_agentcaps *);
-static void subagentx_agentcaps_reset(struct subagentx_agentcaps *);
-static int subagentx_region_start(struct subagentx_region *);
-static int subagentx_region_finalize(struct agentx_pdu *, void *);
-static int subagentx_region_close(struct subagentx_region *);
-static int subagentx_region_close_finalize(struct agentx_pdu *, void *);
-static void subagentx_region_free_finalize(struct subagentx_region *);
-static void subagentx_region_reset(struct subagentx_region *);
-static struct subagentx_index *subagentx_index(struct subagentx_region *,
- struct agentx_varbind *, enum subagentx_index_type);
-static int subagentx_index_start(struct subagentx_index *);
-static int subagentx_index_finalize(struct agentx_pdu *, void *);
-static void subagentx_index_free_finalize(struct subagentx_index *);
-static void subagentx_index_reset(struct subagentx_index *);
-static int subagentx_index_close(struct subagentx_index *);
-static int subagentx_index_close_finalize(struct agentx_pdu *, void *);
-static int subagentx_object_start(struct subagentx_object *);
-static int subagentx_object_finalize(struct agentx_pdu *, void *);
-static int subagentx_object_lock(struct subagentx_object *);
-static void subagentx_object_unlock(struct subagentx_object *);
-static int subagentx_object_close(struct subagentx_object *);
-static int subagentx_object_close_finalize(struct agentx_pdu *, void *);
-static void subagentx_object_free_finalize(struct subagentx_object *);
-static void subagentx_object_reset(struct subagentx_object *);
-static int subagentx_object_cmp(struct subagentx_object *,
- struct subagentx_object *);
-static void subagentx_get_start(struct subagentx_context *,
- struct agentx_pdu *);
-static void subagentx_get_finalize(struct subagentx_get *);
-static void subagentx_get_free(struct subagentx_get *);
-static void subagentx_varbind_start(struct subagentx_varbind *);
-static void subagentx_varbind_finalize(struct subagentx_varbind *);
-static void subagentx_varbind_nosuchobject(struct subagentx_varbind *);
-static void subagentx_varbind_nosuchinstance(struct subagentx_varbind *);
-static void subagentx_varbind_endofmibview(struct subagentx_varbind *);
-static void subagentx_varbind_error_type(struct subagentx_varbind *,
- enum agentx_pdu_error, int);
-static int subagentx_request(struct subagentx *, uint32_t,
- int (*)(struct agentx_pdu *, void *), void *);
-static int subagentx_request_cmp(struct subagentx_request *,
- struct subagentx_request *);
-static int subagentx_strcat(char **, const char *);
-
-RB_PROTOTYPE_STATIC(sa_requests, subagentx_request, sar_sa_requests,
- subagentx_request_cmp)
-RB_PROTOTYPE_STATIC(sac_objects, subagentx_object, sao_sac_objects,
- subagentx_object_cmp)
-
-struct subagentx *
-subagentx(void (*nofd)(struct subagentx *, void *, int), void *cookie)
-{
- struct subagentx *sa;
-
- if ((sa = calloc(1, sizeof(*sa))) == NULL)
- return NULL;
-
- sa->sa_nofd = nofd;
- sa->sa_cookie = cookie;
- sa->sa_fd = -1;
- sa->sa_cstate = SA_CSTATE_CLOSE;
- sa->sa_dstate = SA_DSTATE_OPEN;
- TAILQ_INIT(&(sa->sa_sessions));
- TAILQ_INIT(&(sa->sa_getreqs));
- RB_INIT(&(sa->sa_requests));
-
- subagentx_start(sa);
-
- return sa;
-}
-
-/*
- * subagentx_finalize is not a suitable name for a public API,
- * but use it internally for consistency
- */
-void
-subagentx_connect(struct subagentx *sa, int fd)
-{
- subagentx_finalize(sa, fd);
-}
-
-static void
-subagentx_start(struct subagentx *sa)
-{
-#ifdef AGENTX_DEBUG
- if (sa->sa_cstate != SA_CSTATE_CLOSE ||
- sa->sa_dstate != SA_DSTATE_OPEN)
- subagentx_log_sa_fatalx(sa, "%s: unexpected connect", __func__);
-#endif
- sa->sa_cstate = SA_CSTATE_WAITOPEN;
- sa->sa_nofd(sa, sa->sa_cookie, 0);
-}
-
-static void
-subagentx_finalize(struct subagentx *sa, int fd)
-{
- struct subagentx_session *sas;
-
- if (sa->sa_cstate != SA_CSTATE_WAITOPEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sa_fatalx(sa, "%s: subagentx unexpected connect",
- __func__);
-#else
- subagentx_log_sa_warnx(sa,
- "%s: subagentx unexpected connect: ignoring", __func__);
- return;
-#endif
- }
- if ((sa->sa_ax = agentx_new(fd)) == NULL) {
- subagentx_log_sa_warn(sa, "failed to initialize");
- close(fd);
- subagentx_reset(sa);
- return;
- }
-
- subagentx_log_sa_info(sa, "new connection: %d", fd);
-
- sa->sa_fd = fd;
- sa->sa_cstate = SA_CSTATE_OPEN;
-
- TAILQ_FOREACH(sas, &(sa->sa_sessions), sas_sa_sessions) {
- if (subagentx_session_start(sas) == -1)
- break;
- }
-}
-
-static void
-subagentx_wantwritenow(struct subagentx *sa, int fd)
-{
- subagentx_write(sa);
-}
-
-static void
-subagentx_reset(struct subagentx *sa)
-{
- struct subagentx_session *sas, *tsas;
- struct subagentx_request *sar;
- struct subagentx_get *sag;
-
- agentx_free(sa->sa_ax);
- sa->sa_ax = NULL;
- sa->sa_fd = -1;
-
- sa->sa_cstate = SA_CSTATE_CLOSE;
-
- while ((sar = RB_MIN(sa_requests, &(sa->sa_requests))) != NULL) {
- RB_REMOVE(sa_requests, &(sa->sa_requests), sar);
- free(sar);
- }
- TAILQ_FOREACH_SAFE(sas, &(sa->sa_sessions), sas_sa_sessions, tsas)
- subagentx_session_reset(sas);
- while (!TAILQ_EMPTY(&(sa->sa_getreqs))) {
- sag = TAILQ_FIRST(&(sa->sa_getreqs));
- sag->sag_sac = NULL;
- TAILQ_REMOVE(&(sa->sa_getreqs), sag, sag_sa_getreqs);
- }
-
- if (sa->sa_dstate == SA_DSTATE_CLOSE) {
- subagentx_free_finalize(sa);
- return;
- }
-
- subagentx_start(sa);
-}
-
-void
-subagentx_free(struct subagentx *sa)
-{
- struct subagentx_session *sas, *tsas;
-
- if (sa == NULL)
- return;
-
- if (sa->sa_dstate == SA_DSTATE_CLOSE) {
-/* Malloc throws abort on invalid pointers as well */
- subagentx_log_sa_fatalx(sa, "%s: double free", __func__);
- }
- sa->sa_dstate = SA_DSTATE_CLOSE;
-
- if (!TAILQ_EMPTY(&(sa->sa_sessions))) {
- TAILQ_FOREACH_SAFE(sas, &(sa->sa_sessions), sas_sa_sessions,
- tsas) {
- if (sas->sas_dstate != SA_DSTATE_CLOSE)
- subagentx_session_free(sas);
- }
- } else
- subagentx_free_finalize(sa);
-}
-
-static void
-subagentx_free_finalize(struct subagentx *sa)
-{
-#ifdef AGENTX_DEBUG
- if (sa->sa_dstate != SA_DSTATE_CLOSE)
- subagentx_log_sa_fatalx(sa, "%s: subagentx not closing",
- __func__);
- if (!TAILQ_EMPTY(&(sa->sa_sessions)))
- subagentx_log_sa_fatalx(sa, "%s: subagentx still has sessions",
- __func__);
- if (!RB_EMPTY(&(sa->sa_requests)))
- subagentx_log_sa_fatalx(sa,
- "%s: subagentx still has pending requests", __func__);
-#endif
-
- agentx_free(sa->sa_ax);
- sa->sa_nofd(sa, sa->sa_cookie, 1);
- free(sa);
-}
-
-struct subagentx_session *
-subagentx_session(struct subagentx *sa, uint32_t oid[],
- size_t oidlen, const char *descr, uint8_t timeout)
-{
- struct subagentx_session *sas;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sa_fatalx(sa, "%s: oidlen > %d", __func__,
- SUBAGENTX_OID_MAX_LEN);
-#else
- errno = EINVAL;
- return NULL;
-#endif
- }
- if ((sas = calloc(1, sizeof(*sas))) == NULL)
- return NULL;
-
- sas->sas_sa = sa;
- sas->sas_timeout = timeout;
- for (i = 0; i < oidlen; i++)
- sas->sas_oid.aoi_id[i] = oid[i];
- sas->sas_oid.aoi_idlen = oidlen;
- sas->sas_descr.aos_string = (unsigned char *)strdup(descr);
- if (sas->sas_descr.aos_string == NULL) {
- free(sas);
- return NULL;
- }
- sas->sas_descr.aos_slen = strlen(descr);
- sas->sas_cstate = SA_CSTATE_CLOSE;
- sas->sas_dstate = SA_DSTATE_OPEN;
- TAILQ_INIT(&(sas->sas_contexts));
- TAILQ_INSERT_HEAD(&(sa->sa_sessions), sas, sas_sa_sessions);
-
- if (sa->sa_cstate == SA_CSTATE_OPEN)
- (void) subagentx_session_start(sas);
-
- return sas;
-}
-
-static int
-subagentx_session_start(struct subagentx_session *sas)
-{
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (sa->sa_cstate != SA_CSTATE_OPEN ||
- sas->sas_cstate != SA_CSTATE_CLOSE ||
- sas->sas_dstate != SA_DSTATE_OPEN)
- subagentx_log_sa_fatalx(sa, "%s: unexpected session open",
- __func__);
-#endif
- packetid = agentx_open(sa->sa_ax, sas->sas_timeout, &(sas->sas_oid),
- &(sas->sas_descr));
- if (packetid == 0) {
- subagentx_log_sa_warn(sa, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_OPEN));
- subagentx_reset(sa);
- return -1;
- }
- sas->sas_packetid = packetid;
- subagentx_log_sa_info(sa, "opening session");
- sas->sas_cstate = SA_CSTATE_WAITOPEN;
- return subagentx_request(sa, packetid, subagentx_session_finalize, sas);
-}
-
-static int
-subagentx_session_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_session *sas = cookie;
- struct subagentx *sa = sas->sas_sa;
- struct subagentx_context *sac;
-
-#ifdef AGENTX_DEBUG
- if (sas->sas_cstate != SA_CSTATE_WAITOPEN)
- subagentx_log_sa_fatalx(sa, "%s: not expecting new session",
- __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- subagentx_log_sa_warnx(sa, "failed to open session: %s",
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- subagentx_reset(sa);
- return -1;
- }
-
- sas->sas_id = pdu->ap_header.aph_sessionid;
- sas->sas_cstate = SA_CSTATE_OPEN;
-
- if (sas->sas_dstate == SA_DSTATE_CLOSE) {
- subagentx_session_close(sas, AGENTX_CLOSE_SHUTDOWN);
- return 0;
- }
-
- subagentx_log_sas_info(sas, "open");
-
- TAILQ_FOREACH(sac, &(sas->sas_contexts), sac_sas_contexts)
- subagentx_context_start(sac);
- return 0;
-}
-
-static int
-subagentx_session_close(struct subagentx_session *sas,
- enum agentx_close_reason reason)
-{
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (sas->sas_cstate != SA_CSTATE_OPEN)
- subagentx_log_sa_fatalx(sa, "%s: unexpected session close",
- __func__);
-#endif
- if ((packetid = agentx_close(sa->sa_ax, sas->sas_id, reason)) == 0) {
- subagentx_log_sas_warn(sas, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_CLOSE));
- subagentx_reset(sa);
- return -1;
- }
-
- subagentx_log_sas_info(sas, "closing session: %s",
- agentx_closereason2string(reason));
-
- sas->sas_cstate = SA_CSTATE_WAITCLOSE;
- return subagentx_request(sa, packetid, subagentx_session_close_finalize,
- sas);
-}
-
-static int
-subagentx_session_close_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_session *sas = cookie;
- struct subagentx *sa = sas->sas_sa;
- struct subagentx_context *sac, *tsac;
-
-#ifdef AGENTX_DEBUG
- if (sas->sas_cstate != SA_CSTATE_WAITCLOSE)
- subagentx_log_sas_fatalx(sas, "%s: not expecting session close",
- __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- subagentx_log_sas_warnx(sas, "failed to close session: %s",
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- subagentx_reset(sa);
- return -1;
- }
-
- sas->sas_cstate = SA_CSTATE_CLOSE;
-
- subagentx_log_sas_info(sas, "closed");
-
- TAILQ_FOREACH_SAFE(sac, &(sas->sas_contexts), sac_sas_contexts, tsac)
- subagentx_context_reset(sac);
-
- if (sas->sas_dstate == SA_DSTATE_CLOSE)
- subagentx_session_free_finalize(sas);
- else {
- if (sa->sa_cstate == SA_CSTATE_OPEN)
- if (subagentx_session_start(sas) == -1)
- return -1;
- }
- return 0;
-}
-
-void
-subagentx_session_free(struct subagentx_session *sas)
-{
- struct subagentx_context *sac, *tsac;
-
- if (sas == NULL)
- return;
-
- if (sas->sas_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sas_fatalx(sas, "%s: double free", __func__);
-
- sas->sas_dstate = SA_DSTATE_CLOSE;
-
- if (sas->sas_cstate == SA_CSTATE_OPEN)
- (void) subagentx_session_close(sas, AGENTX_CLOSE_SHUTDOWN);
-
- TAILQ_FOREACH_SAFE(sac, &(sas->sas_contexts), sac_sas_contexts, tsac) {
- if (sac->sac_dstate != SA_DSTATE_CLOSE)
- subagentx_context_free(sac);
- }
-
- if (sas->sas_cstate == SA_CSTATE_CLOSE)
- subagentx_session_free_finalize(sas);
-}
-
-static void
-subagentx_session_free_finalize(struct subagentx_session *sas)
-{
- struct subagentx *sa = sas->sas_sa;
-
-#ifdef AGENTX_DEBUG
- if (sas->sas_cstate != SA_CSTATE_CLOSE)
- subagentx_log_sas_fatalx(sas, "%s: free without closing",
- __func__);
- if (!TAILQ_EMPTY(&(sas->sas_contexts)))
- subagentx_log_sas_fatalx(sas,
- "%s: subagentx still has contexts", __func__);
-#endif
-
- TAILQ_REMOVE(&(sa->sa_sessions), sas, sas_sa_sessions);
- free(sas->sas_descr.aos_string);
- free(sas);
-
- if (TAILQ_EMPTY(&(sa->sa_sessions)) && sa->sa_dstate == SA_DSTATE_CLOSE)
- subagentx_free_finalize(sa);
-}
-
-static void
-subagentx_session_reset(struct subagentx_session *sas)
-{
- struct subagentx_context *sac, *tsac;
-
- sas->sas_cstate = SA_CSTATE_CLOSE;
-
- TAILQ_FOREACH_SAFE(sac, &(sas->sas_contexts), sac_sas_contexts, tsac)
- subagentx_context_reset(sac);
-
- if (sas->sas_dstate == SA_DSTATE_CLOSE)
- subagentx_session_free_finalize(sas);
-}
-
-struct subagentx_context *
-subagentx_context(struct subagentx_session *sas, const char *name)
-{
- struct subagentx_context *sac;
-
- if (sas->sas_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sas_fatalx(sas, "%s: use after free", __func__);
-
- if ((sac = calloc(1, sizeof(*sac))) == NULL)
- return NULL;
-
- sac->sac_sas = sas;
- sac->sac_name_default = (name == NULL);
- if (name != NULL) {
- sac->sac_name.aos_string = (unsigned char *)strdup(name);
- if (sac->sac_name.aos_string == NULL) {
- free(sac);
- return NULL;
- }
- sac->sac_name.aos_slen = strlen(name);
- }
- sac->sac_cstate = sas->sas_cstate == SA_CSTATE_OPEN ?
- SA_CSTATE_OPEN : SA_CSTATE_CLOSE;
- sac->sac_dstate = SA_DSTATE_OPEN;
- TAILQ_INIT(&(sac->sac_agentcaps));
- TAILQ_INIT(&(sac->sac_regions));
-
- TAILQ_INSERT_HEAD(&(sas->sas_contexts), sac, sac_sas_contexts);
-
- return sac;
-}
-
-static void
-subagentx_context_start(struct subagentx_context *sac)
-{
- struct subagentx_agentcaps *saa;
- struct subagentx_region *sar;
-
-#ifdef AGENTX_DEBUG
- if (sac->sac_cstate != SA_CSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected context start",
- __func__);
-#endif
- sac->sac_cstate = SA_CSTATE_OPEN;
-
- TAILQ_FOREACH(saa, &(sac->sac_agentcaps), saa_sac_agentcaps) {
- if (subagentx_agentcaps_start(saa) == -1)
- return;
- }
- TAILQ_FOREACH(sar, &(sac->sac_regions), sar_sac_regions) {
- if (subagentx_region_start(sar) == -1)
- return;
- }
-}
-
-uint32_t
-subagentx_context_uptime(struct subagentx_context *sac)
-{
- struct timespec cur, res;
-
- if (sac->sac_sysuptimespec.tv_sec == 0 &&
- sac->sac_sysuptimespec.tv_nsec == 0)
- return 0;
-
- (void) clock_gettime(CLOCK_MONOTONIC, &cur);
-
- timespecsub(&cur, &(sac->sac_sysuptimespec), &res);
-
- return sac->sac_sysuptime +
- (uint32_t) ((res.tv_sec * 100) + (res.tv_nsec / 10000000));
-}
-
-struct subagentx_object *
-subagentx_context_object_find(struct subagentx_context *sac,
- const uint32_t oid[], size_t oidlen, int active, int instance)
-{
- struct subagentx_object *sao, sao_search;
- size_t i;
-
- for (i = 0; i < oidlen; i++)
- sao_search.sao_oid.aoi_id[i] = oid[i];
- sao_search.sao_oid.aoi_idlen = oidlen;
-
- sao = RB_FIND(sac_objects, &(sac->sac_objects), &sao_search);
- while (sao == NULL && !instance && sao_search.sao_oid.aoi_idlen > 0) {
- sao = RB_FIND(sac_objects, &(sac->sac_objects), &sao_search);
- sao_search.sao_oid.aoi_idlen--;
- }
- if (active && sao != NULL && sao->sao_cstate != SA_CSTATE_OPEN)
- return NULL;
- return sao;
-}
-
-struct subagentx_object *
-subagentx_context_object_nfind(struct subagentx_context *sac,
- const uint32_t oid[], size_t oidlen, int active, int inclusive)
-{
- struct subagentx_object *sao, sao_search;
- size_t i;
-
- for (i = 0; i < oidlen; i++)
- sao_search.sao_oid.aoi_id[i] = oid[i];
- sao_search.sao_oid.aoi_idlen = oidlen;
-
- sao = RB_NFIND(sac_objects, &(sac->sac_objects), &sao_search);
- if (!inclusive && sao != NULL &&
- agentx_oid_cmp(&(sao_search.sao_oid), &(sao->sao_oid)) <= 0) {
- sao = RB_NEXT(sac_objects, &(sac->sac_objects), sao);
- }
-
- while (active && sao != NULL && sao->sao_cstate != SA_CSTATE_OPEN)
- sao = RB_NEXT(sac_objects, &(sac->sac_objects), sao);
- return sao;
-}
-
-void
-subagentx_context_free(struct subagentx_context *sac)
-{
- struct subagentx_agentcaps *saa, *tsaa;
- struct subagentx_region *sar, *tsar;
-
- if (sac == NULL)
- return;
-
-#ifdef AGENTX_DEBUG
- if (sac->sac_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: double free", __func__);
-#endif
- sac->sac_dstate = SA_DSTATE_CLOSE;
-
- TAILQ_FOREACH_SAFE(saa, &(sac->sac_agentcaps), saa_sac_agentcaps,
- tsaa) {
- if (saa->saa_dstate != SA_DSTATE_CLOSE)
- subagentx_agentcaps_free(saa);
- }
- TAILQ_FOREACH_SAFE(sar, &(sac->sac_regions), sar_sac_regions, tsar) {
- if (sar->sar_dstate != SA_DSTATE_CLOSE)
- subagentx_region_free(sar);
- }
-}
-
-static void
-subagentx_context_free_finalize(struct subagentx_context *sac)
-{
- struct subagentx_session *sas = sac->sac_sas;
-
-#ifdef AGENTX_DEBUG
- if (sac->sac_dstate != SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected context free",
- __func__);
-#endif
- if (!TAILQ_EMPTY(&(sac->sac_regions)) ||
- !TAILQ_EMPTY(&(sac->sac_agentcaps)))
- return;
- TAILQ_REMOVE(&(sas->sas_contexts), sac, sac_sas_contexts);
- free(sac->sac_name.aos_string);
- free(sac);
-}
-
-static void
-subagentx_context_reset(struct subagentx_context *sac)
-{
- struct subagentx_agentcaps *saa, *tsaa;
- struct subagentx_region *sar, *tsar;
-
- sac->sac_cstate = SA_CSTATE_CLOSE;
- sac->sac_sysuptimespec.tv_sec = 0;
- sac->sac_sysuptimespec.tv_nsec = 0;
-
- TAILQ_FOREACH_SAFE(saa, &(sac->sac_agentcaps), saa_sac_agentcaps, tsaa)
- subagentx_agentcaps_reset(saa);
- TAILQ_FOREACH_SAFE(sar, &(sac->sac_regions), sar_sac_regions, tsar)
- subagentx_region_reset(sar);
-
- if (sac->sac_dstate == SA_DSTATE_CLOSE)
- subagentx_context_free_finalize(sac);
-}
-
-struct subagentx_agentcaps *
-subagentx_agentcaps(struct subagentx_context *sac, uint32_t oid[],
- size_t oidlen, const char *descr)
-{
- struct subagentx_agentcaps *saa;
- size_t i;
-
- if (sac->sac_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: use after free", __func__);
-
- if ((saa = calloc(1, sizeof(*saa))) == NULL)
- return NULL;
-
- saa->saa_sac = sac;
- for (i = 0; i < oidlen; i++)
- saa->saa_oid.aoi_id[i] = oid[i];
- saa->saa_oid.aoi_idlen = oidlen;
- saa->saa_descr.aos_string = (unsigned char *)strdup(descr);
- if (saa->saa_descr.aos_string == NULL) {
- free(saa);
- return NULL;
- }
- saa->saa_descr.aos_slen = strlen(descr);
- saa->saa_cstate = SA_CSTATE_CLOSE;
- saa->saa_dstate = SA_DSTATE_OPEN;
-
- TAILQ_INSERT_TAIL(&(sac->sac_agentcaps), saa, saa_sac_agentcaps);
-
- if (sac->sac_cstate == SA_CSTATE_OPEN)
- subagentx_agentcaps_start(saa);
-
- return saa;
-}
-
-static int
-subagentx_agentcaps_start(struct subagentx_agentcaps *saa)
-{
- struct subagentx_context *sac = saa->saa_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (sac->sac_cstate != SA_CSTATE_OPEN ||
- saa->saa_cstate != SA_CSTATE_CLOSE ||
- saa->saa_dstate != SA_DSTATE_OPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: unexpected region registration", __func__);
-#endif
-
- packetid = agentx_addagentcaps(sa->sa_ax, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), &(saa->saa_oid), &(saa->saa_descr));
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_ADDAGENTCAPS));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "agentcaps %s: opening",
- agentx_oid2string(&(saa->saa_oid)));
- saa->saa_cstate = SA_CSTATE_WAITOPEN;
- return subagentx_request(sa, packetid, subagentx_agentcaps_finalize,
- saa);
-}
-
-static int
-subagentx_agentcaps_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_agentcaps *saa = cookie;
- struct subagentx_context *sac = saa->saa_sac;
-
-#ifdef AGENTX_DEBUG
- if (saa->saa_cstate != SA_CSTATE_WAITOPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: not expecting agentcaps open", __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- /* Agentcaps failing is nothing too serious */
- subagentx_log_sac_warn(sac, "agentcaps %s: %s",
- agentx_oid2string(&(saa->saa_oid)),
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- saa->saa_cstate = SA_CSTATE_CLOSE;
- return 0;
- }
-
- saa->saa_cstate = SA_CSTATE_OPEN;
-
- subagentx_log_sac_info(sac, "agentcaps %s: open",
- agentx_oid2string(&(saa->saa_oid)));
-
- if (saa->saa_dstate == SA_DSTATE_CLOSE)
- subagentx_agentcaps_close(saa);
-
- return 0;
-}
-
-static int
-subagentx_agentcaps_close(struct subagentx_agentcaps *saa)
-{
- struct subagentx_context *sac = saa->saa_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (saa->saa_cstate != SA_CSTATE_OPEN)
- subagentx_log_sac_fatalx(sac, "%s: unexpected agentcaps close",
- __func__);
-#endif
-
- saa->saa_cstate = SA_CSTATE_WAITCLOSE;
- if (sas->sas_cstate == SA_CSTATE_WAITCLOSE)
- return 0;
-
- packetid = agentx_removeagentcaps(sa->sa_ax, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), &(saa->saa_oid));
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_REMOVEAGENTCAPS));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "agentcaps %s: closing",
- agentx_oid2string(&(saa->saa_oid)));
- return subagentx_request(sa, packetid,
- subagentx_agentcaps_close_finalize, saa);
-}
-
-static int
-subagentx_agentcaps_close_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_agentcaps *saa = cookie;
- struct subagentx_context *sac = saa->saa_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
-
-#ifdef AGENTX_DEBUG
- if (saa->saa_cstate != SA_CSTATE_WAITCLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected agentcaps close",
- __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- subagentx_log_sac_warnx(sac, "agentcaps %s: %s",
- agentx_oid2string(&(saa->saa_oid)),
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- subagentx_reset(sa);
- return -1;
- }
-
- saa->saa_cstate = SA_CSTATE_CLOSE;
-
- subagentx_log_sac_info(sac, "agentcaps %s: closed",
- agentx_oid2string(&(saa->saa_oid)));
-
- if (saa->saa_dstate == SA_DSTATE_CLOSE) {
- subagentx_agentcaps_free_finalize(saa);
- return 0;
- } else {
- if (sac->sac_cstate == SA_CSTATE_OPEN) {
- if (subagentx_agentcaps_start(saa) == -1)
- return -1;
- }
- }
- return 0;
-}
-
-void
-subagentx_agentcaps_free(struct subagentx_agentcaps *saa)
-{
- if (saa == NULL)
- return;
-
- if (saa->saa_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(saa->saa_sac, "%s: double free",
- __func__);
-
- saa->saa_dstate = SA_DSTATE_CLOSE;
-
- if (saa->saa_cstate == SA_CSTATE_OPEN) {
- if (subagentx_agentcaps_close(saa) == -1)
- return;
- }
-
- if (saa->saa_cstate == SA_CSTATE_CLOSE)
- subagentx_agentcaps_free_finalize(saa);
-}
-
-static void
-subagentx_agentcaps_free_finalize(struct subagentx_agentcaps *saa)
-{
- struct subagentx_context *sac = saa->saa_sac;
-
-#ifdef AGENTX_DEBUG
- if (saa->saa_dstate != SA_DSTATE_CLOSE ||
- saa->saa_cstate != SA_CSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected free", __func__);
-#endif
-
- TAILQ_REMOVE(&(sac->sac_agentcaps), saa, saa_sac_agentcaps);
- free(saa->saa_descr.aos_string);
- free(saa);
-
- if (sac->sac_dstate == SA_DSTATE_CLOSE)
- subagentx_context_free_finalize(sac);
-}
-
-static void
-subagentx_agentcaps_reset(struct subagentx_agentcaps *saa)
-{
- saa->saa_cstate = SA_CSTATE_CLOSE;
-
- if (saa->saa_dstate == SA_DSTATE_CLOSE)
- subagentx_agentcaps_free_finalize(saa);
-}
-
-struct subagentx_region *
-subagentx_region(struct subagentx_context *sac, uint32_t oid[],
- size_t oidlen, uint8_t timeout)
-{
- struct subagentx_region *sar;
- struct agentx_oid tmpoid;
- size_t i;
-
- if (sac->sac_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: use after free", __func__);
- if (oidlen < 1) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sac, "%s: oidlen == 0", __func__);
-#else
- errno = EINVAL;
- return NULL;
-#endif
- }
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sac, "%s: oidlen > %d", __func__,
- SUBAGENTX_OID_MAX_LEN);
-#else
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- for (i = 0; i < oidlen; i++)
- tmpoid.aoi_id[i] = oid[i];
- tmpoid.aoi_idlen = oidlen;
- TAILQ_FOREACH(sar, &(sac->sac_regions), sar_sac_regions) {
- if (agentx_oid_cmp(&(sar->sar_oid), &tmpoid) == 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sac,
- "%s: duplicate region registration", __func__);
-#else
- errno = EINVAL;
- return NULL;
-#endif
- }
- }
-
- if ((sar = calloc(1, sizeof(*sar))) == NULL)
- return NULL;
-
- sar->sar_sac = sac;
- sar->sar_timeout = timeout;
- sar->sar_priority = AGENTX_PRIORITY_DEFAULT;
- bcopy(&tmpoid, &(sar->sar_oid), sizeof(sar->sar_oid));
- sar->sar_cstate = SA_CSTATE_CLOSE;
- sar->sar_dstate = SA_DSTATE_OPEN;
- TAILQ_INIT(&(sar->sar_indices));
- TAILQ_INIT(&(sar->sar_objects));
-
- TAILQ_INSERT_HEAD(&(sac->sac_regions), sar, sar_sac_regions);
-
- if (sac->sac_cstate == SA_CSTATE_OPEN)
- (void) subagentx_region_start(sar);
-
- return sar;
-}
-
-static int
-subagentx_region_start(struct subagentx_region *sar)
-{
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (sac->sac_cstate != SA_CSTATE_OPEN ||
- sar->sar_cstate != SA_CSTATE_CLOSE ||
- sar->sar_dstate != SA_DSTATE_OPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: unexpected region registration", __func__);
-#endif
-
- packetid = agentx_register(sa->sa_ax, 0, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), sar->sar_timeout, sar->sar_priority,
- 0, &(sar->sar_oid), 0);
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_REGISTER));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "region %s: opening",
- agentx_oid2string(&(sar->sar_oid)));
- sar->sar_cstate = SA_CSTATE_WAITOPEN;
- return subagentx_request(sa, packetid, subagentx_region_finalize, sar);
-}
-
-static int
-subagentx_region_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_region *sar = cookie;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct subagentx_index *sai;
- struct subagentx_object *sao;
-
-#ifdef AGENTX_DEBUG
- if (sar->sar_cstate != SA_CSTATE_WAITOPEN)
- subagentx_log_sac_fatalx(sac, "%s: not expecting region open",
- __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error == AGENTX_PDU_ERROR_NOERROR) {
- sar->sar_cstate = SA_CSTATE_OPEN;
- subagentx_log_sac_info(sac, "region %s: open",
- agentx_oid2string(&(sar->sar_oid)));
- } else if (pdu->ap_payload.ap_response.ap_error ==
- AGENTX_PDU_ERROR_DUPLICATEREGISTRATION) {
- sar->sar_cstate = SA_CSTATE_CLOSE;
- /* Try at lower priority: first come first serve */
- if ((++sar->sar_priority) != 0) {
- subagentx_log_sac_warnx(sac, "region %s: duplicate, "
- "reducing priority",
- agentx_oid2string(&(sar->sar_oid)));
- return subagentx_region_start(sar);
- }
- subagentx_log_sac_info(sac, "region %s: duplicate, can't "
- "reduce priority, ignoring",
- agentx_oid2string(&(sar->sar_oid)));
- } else if (pdu->ap_payload.ap_response.ap_error ==
- AGENTX_PDU_ERROR_REQUESTDENIED) {
- sar->sar_cstate = SA_CSTATE_CLOSE;
- subagentx_log_sac_warnx(sac, "region %s: %s",
- agentx_oid2string(&(sar->sar_oid)),
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- /*
- * If we can't register a region, related objects are useless.
- * But no need to retry.
- */
- return 0;
- } else {
- subagentx_log_sac_info(sac, "region %s: %s",
- agentx_oid2string(&(sar->sar_oid)),
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- subagentx_reset(sa);
- return -1;
- }
-
- if (sar->sar_dstate == SA_DSTATE_CLOSE) {
- if (subagentx_region_close(sar) == -1)
- return -1;
- } else {
- TAILQ_FOREACH(sai, &(sar->sar_indices), sai_sar_indices) {
- if (subagentx_index_start(sai) == -1)
- return -1;
- }
- TAILQ_FOREACH(sao, &(sar->sar_objects), sao_sar_objects) {
- if (subagentx_object_start(sao) == -1)
- return -1;
- }
- }
- return 0;
-}
-
-static int
-subagentx_region_close(struct subagentx_region *sar)
-{
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (sar->sar_cstate != SA_CSTATE_OPEN)
- subagentx_log_sac_fatalx(sac, "%s: unexpected region close",
- __func__);
-#endif
-
- sar->sar_cstate = SA_CSTATE_WAITCLOSE;
- if (sas->sas_cstate == SA_CSTATE_WAITCLOSE)
- return 0;
-
- packetid = agentx_unregister(sa->sa_ax, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), sar->sar_priority, 0, &(sar->sar_oid),
- 0);
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_UNREGISTER));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "region %s: closing",
- agentx_oid2string(&(sar->sar_oid)));
- return subagentx_request(sa, packetid, subagentx_region_close_finalize,
- sar);
-}
-
-static int
-subagentx_region_close_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_region *sar = cookie;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
-
-#ifdef AGENTX_DEBUG
- if (sar->sar_cstate != SA_CSTATE_WAITCLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected region close",
- __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- subagentx_log_sac_warnx(sac, "closing %s: %s",
- agentx_oid2string(&(sar->sar_oid)),
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- subagentx_reset(sa);
- return -1;
- }
-
- sar->sar_priority = AGENTX_PRIORITY_DEFAULT;
- sar->sar_cstate = SA_CSTATE_CLOSE;
-
- subagentx_log_sac_info(sac, "region %s: closed",
- agentx_oid2string(&(sar->sar_oid)));
-
- if (sar->sar_dstate == SA_DSTATE_CLOSE) {
- subagentx_region_free_finalize(sar);
- return 0;
- } else {
- if (sac->sac_cstate == SA_CSTATE_OPEN) {
- if (subagentx_region_start(sar) == -1)
- return -1;
- }
- }
- return 0;
-}
-
-void
-subagentx_region_free(struct subagentx_region *sar)
-{
- struct subagentx_index *sai, *tsai;
- struct subagentx_object *sao, *tsao;
-
- if (sar == NULL)
- return;
-
- if (sar->sar_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: double free",
- __func__);
-
- sar->sar_dstate = SA_DSTATE_CLOSE;
-
- TAILQ_FOREACH_SAFE(sai, &(sar->sar_indices), sai_sar_indices, tsai) {
- if (sai->sai_dstate != SA_DSTATE_CLOSE)
- subagentx_index_free(sai);
- }
-
- TAILQ_FOREACH_SAFE(sao, &(sar->sar_objects), sao_sar_objects, tsao) {
- if (sao->sao_dstate != SA_DSTATE_CLOSE)
- subagentx_object_free(sao);
- }
-
- if (sar->sar_cstate == SA_CSTATE_OPEN) {
- if (subagentx_region_close(sar) == -1)
- return;
- }
-
- if (sar->sar_cstate == SA_CSTATE_CLOSE)
- subagentx_region_free_finalize(sar);
-}
-
-static void
-subagentx_region_free_finalize(struct subagentx_region *sar)
-{
- struct subagentx_context *sac = sar->sar_sac;
-
-#ifdef AGENTX_DEBUG
- if (sar->sar_dstate != SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected free", __func__);
-#endif
-
- if (!TAILQ_EMPTY(&(sar->sar_indices)) ||
- !TAILQ_EMPTY(&(sar->sar_objects)))
- return;
-
- if (sar->sar_cstate != SA_CSTATE_CLOSE)
- return;
-
- TAILQ_REMOVE(&(sac->sac_regions), sar, sar_sac_regions);
- free(sar);
-
- if (sac->sac_dstate == SA_DSTATE_CLOSE)
- subagentx_context_free_finalize(sac);
-}
-
-static void
-subagentx_region_reset(struct subagentx_region *sar)
-{
- struct subagentx_index *sai, *tsai;
- struct subagentx_object *sao, *tsao;
-
- sar->sar_cstate = SA_CSTATE_CLOSE;
- sar->sar_priority = AGENTX_PRIORITY_DEFAULT;
-
- TAILQ_FOREACH_SAFE(sai, &(sar->sar_indices), sai_sar_indices, tsai)
- subagentx_index_reset(sai);
- TAILQ_FOREACH_SAFE(sao, &(sar->sar_objects), sao_sar_objects, tsao)
- subagentx_object_reset(sao);
-
- if (sar->sar_dstate == SA_DSTATE_CLOSE)
- subagentx_region_free_finalize(sar);
-}
-
-struct subagentx_index *
-subagentx_index_integer_new(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_INTEGER;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_uint32 = 0;
-
- return subagentx_index(sar, &vb, SAI_TYPE_NEW);
-}
-
-struct subagentx_index *
-subagentx_index_integer_any(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_INTEGER;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_uint32 = 0;
-
- return subagentx_index(sar, &vb, SAI_TYPE_ANY);
-}
-
-struct subagentx_index *
-subagentx_index_integer_value(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen, uint32_t value)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_INTEGER;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_uint32 = value;
-
- return subagentx_index(sar, &vb, SAI_TYPE_VALUE);
-}
-
-struct subagentx_index *
-subagentx_index_integer_dynamic(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_INTEGER;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
-
- return subagentx_index(sar, &vb, SAI_TYPE_DYNAMIC);
-}
-
-struct subagentx_index *
-subagentx_index_string_dynamic(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_OCTETSTRING;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_ostring.aos_slen = 0;
- vb.avb_data.avb_ostring.aos_string = NULL;
-
- return subagentx_index(sar, &vb, SAI_TYPE_DYNAMIC);
-}
-
-struct subagentx_index *
-subagentx_index_nstring_dynamic(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen, size_t vlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
- if (vlen == 0 || vlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: invalid string "
- "length: %zu\n", __func__, vlen);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: invalid string "
- "length: %zu\n", __func__, vlen);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_OCTETSTRING;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_ostring.aos_slen = vlen;
- vb.avb_data.avb_ostring.aos_string = NULL;
-
- return subagentx_index(sar, &vb, SAI_TYPE_DYNAMIC);
-}
-
-struct subagentx_index *
-subagentx_index_oid_dynamic(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_OID;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_oid.aoi_idlen = 0;
-
- return subagentx_index(sar, &vb, SAI_TYPE_DYNAMIC);
-}
-
-struct subagentx_index *
-subagentx_index_noid_dynamic(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen, size_t vlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
- if (vlen == 0 || vlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: invalid string "
- "length: %zu\n", __func__, vlen);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: invalid string "
- "length: %zu\n", __func__, vlen);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_OID;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_oid.aoi_idlen = oidlen;
- vb.avb_data.avb_oid.aoi_idlen = vlen;
-
- return subagentx_index(sar, &vb, SAI_TYPE_DYNAMIC);
-}
-
-struct subagentx_index *
-subagentx_index_ipaddress_dynamic(struct subagentx_region *sar, uint32_t oid[],
- size_t oidlen)
-{
- struct agentx_varbind vb;
- size_t i;
-
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- vb.avb_type = AGENTX_DATA_TYPE_IPADDRESS;
- for (i = 0; i < oidlen; i++)
- vb.avb_oid.aoi_id[i] = oid[i];
- vb.avb_data.avb_ostring.aos_string = NULL;
- vb.avb_oid.aoi_idlen = oidlen;
-
- return subagentx_index(sar, &vb, SAI_TYPE_DYNAMIC);
-}
-
-static struct subagentx_index *
-subagentx_index(struct subagentx_region *sar, struct agentx_varbind *vb,
- enum subagentx_index_type type)
-{
- struct subagentx_index *sai;
-
- if (sar->sar_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: use after free",
- __func__);
- if (agentx_oid_cmp(&(sar->sar_oid), &(vb->avb_oid)) != -2) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oid is not child "
- "of region %s", __func__,
- agentx_oid2string(&(vb->avb_oid)));
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oid is not child of "
- "region %s", __func__, agentx_oid2string(&(vb->avb_oid)));
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- if ((sai = calloc(1, sizeof(*sai))) == NULL)
- return NULL;
-
- sai->sai_sar = sar;
- sai->sai_type = type;
- bcopy(vb, &(sai->sai_vb), sizeof(*vb));
- sai->sai_cstate = SA_CSTATE_CLOSE;
- sai->sai_dstate = SA_DSTATE_OPEN;
- TAILQ_INSERT_HEAD(&(sar->sar_indices), sai, sai_sar_indices);
-
- if (sar->sar_cstate == SA_CSTATE_OPEN)
- subagentx_index_start(sai);
-
- return sai;
-}
-
-static int
-subagentx_index_start(struct subagentx_index *sai)
-{
- struct subagentx_region *sar = sai->sai_sar;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
- int flags = 0;
-
-#ifdef AGENTX_DEBUG
- if (sar->sar_cstate != SA_CSTATE_OPEN ||
- sai->sai_cstate != SA_CSTATE_CLOSE ||
- sai->sai_dstate != SA_DSTATE_OPEN)
- subagentx_log_sac_fatalx(sac, "%s: unexpected index allocation",
- __func__);
-#endif
-
- sai->sai_cstate = SA_CSTATE_WAITOPEN;
-
- if (sai->sai_type == SAI_TYPE_NEW)
- flags = AGENTX_PDU_FLAG_NEW_INDEX;
- else if (sai->sai_type == SAI_TYPE_ANY)
- flags = AGENTX_PDU_FLAG_ANY_INDEX;
- else if (sai->sai_type == SAI_TYPE_DYNAMIC) {
- subagentx_index_finalize(NULL, sai);
- return 0;
- }
-
- /* We might be able to bundle, but if we fail we'd have to reorganise */
- packetid = agentx_indexallocate(sa->sa_ax, flags, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), &(sai->sai_vb), 1);
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_INDEXDEALLOCATE));
- subagentx_reset(sa);
- return -1;
- }
- if (sai->sai_type == SAI_TYPE_VALUE)
- subagentx_log_sac_info(sac, "index %s: allocating '%u'",
- agentx_oid2string(&(sai->sai_vb.avb_oid)),
- sai->sai_vb.avb_data.avb_uint32);
- else if (sai->sai_type == SAI_TYPE_ANY)
- subagentx_log_sac_info(sac, "index %s: allocating any index",
- agentx_oid2string(&(sai->sai_vb.avb_oid)));
- else if (sai->sai_type == SAI_TYPE_NEW)
- subagentx_log_sac_info(sac, "index %s: allocating new index",
- agentx_oid2string(&(sai->sai_vb.avb_oid)));
-
- return subagentx_request(sa, packetid, subagentx_index_finalize, sai);
-}
-
-static int
-subagentx_index_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_index *sai = cookie;
- struct subagentx_region *sar = sai->sai_sar;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct agentx_pdu_response *resp;
- size_t i;
-
-#ifdef AGENTX_DEBUG
- if (sai->sai_cstate != SA_CSTATE_WAITOPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: not expecting index allocate", __func__);
-#endif
- if (sai->sai_type == SAI_TYPE_DYNAMIC) {
- sai->sai_cstate = SA_CSTATE_OPEN;
- return 0;
- }
-
- resp = &(pdu->ap_payload.ap_response);
- if (resp->ap_error != AGENTX_PDU_ERROR_NOERROR) {
- sai->sai_cstate = SA_CSTATE_CLOSE;
- subagentx_log_sac_warnx(sac, "index %s: %s",
- agentx_oid2string(&(sar->sar_oid)),
- agentx_error2string(resp->ap_error));
- return 0;
- }
- sai->sai_cstate = SA_CSTATE_OPEN;
- if (resp->ap_nvarbind != 1) {
- subagentx_log_sac_warnx(sac, "index %s: unexpected number of "
- "indices", agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- if (resp->ap_varbindlist[0].avb_type != sai->sai_vb.avb_type) {
- subagentx_log_sac_warnx(sac, "index %s: unexpected index type",
- agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- if (agentx_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
- &(sai->sai_vb.avb_oid)) != 0) {
- subagentx_log_sac_warnx(sac, "index %s: unexpected oid",
- agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
-
- switch (sai->sai_vb.avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
- if (sai->sai_type == SAI_TYPE_NEW ||
- sai->sai_type == SAI_TYPE_ANY)
- sai->sai_vb.avb_data.avb_uint32 =
- resp->ap_varbindlist[0].avb_data.avb_uint32;
- else if (sai->sai_vb.avb_data.avb_uint32 !=
- resp->ap_varbindlist[0].avb_data.avb_uint32) {
- subagentx_log_sac_warnx(sac, "index %s: unexpected "
- "index value", agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "index %s: allocated '%u'",
- agentx_oid2string(&(sai->sai_vb.avb_oid)),
- sai->sai_vb.avb_data.avb_uint32);
- break;
- default:
- subagentx_log_sac_fatalx(sac, "%s: Unsupported index type",
- __func__);
- }
-
- if (sai->sai_dstate == SA_DSTATE_CLOSE)
- return subagentx_index_close(sai);
-
- /* TODO Make use of range_subid register */
- for (i = 0; i < sai->sai_objectlen; i++) {
- if (sai->sai_object[i]->sao_dstate == SA_DSTATE_OPEN) {
- if (subagentx_object_start(sai->sai_object[i]) == -1)
- return -1;
- }
- }
- return 0;
-}
-
-void
-subagentx_index_free(struct subagentx_index *sai)
-{
- size_t i;
- struct subagentx_object *sao;
-
- if (sai == NULL)
- return;
-
- if (sai->sai_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sai->sai_sar->sar_sac,
- "%s: double free", __func__);
-
- /* TODO Do a range_subid unregister before freeing */
- for (i = 0; i < sai->sai_objectlen; i++) {
- sao = sai->sai_object[i];
- if (sao->sao_dstate != SA_DSTATE_CLOSE) {
- subagentx_object_free(sao);
- if (sai->sai_object[i] != sao)
- i--;
- }
- }
-
- sai->sai_dstate = SA_DSTATE_CLOSE;
-
- if (sai->sai_cstate == SA_CSTATE_OPEN)
- (void) subagentx_index_close(sai);
- else if (sai->sai_cstate == SA_CSTATE_CLOSE)
- subagentx_index_free_finalize(sai);
-}
-
-static void
-subagentx_index_free_finalize(struct subagentx_index *sai)
-{
- struct subagentx_region *sar = sai->sai_sar;
-
-#ifdef AGENTX_DEBUG
- if (sai->sai_dstate != SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: unexpected free",
- __func__);
- if (sai->sai_cstate != SA_CSTATE_CLOSE)
- subagentx_log_sac_fatalx(sar->sar_sac,
- "%s: free without deallocating", __func__);
-#endif
-
- if (sai->sai_objectlen != 0)
- return;
-
- TAILQ_REMOVE(&(sar->sar_indices), sai, sai_sar_indices);
- agentx_varbind_free(&(sai->sai_vb));
- free(sai->sai_object);
- free(sai);
- if (sar->sar_dstate == SA_DSTATE_CLOSE)
- subagentx_region_free_finalize(sar);
-}
-
-static void
-subagentx_index_reset(struct subagentx_index *sai)
-{
- sai->sai_cstate = SA_CSTATE_CLOSE;
-
- if (sai->sai_dstate == SA_DSTATE_CLOSE)
- subagentx_index_free_finalize(sai);
-}
-
-static int
-subagentx_index_close(struct subagentx_index *sai)
-{
- struct subagentx_region *sar = sai->sai_sar;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- uint32_t packetid;
-
-#ifdef AGENTX_DEBUG
- if (sai->sai_cstate != SA_CSTATE_OPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: unexpected index deallocation", __func__);
-#endif
-
- sai->sai_cstate = SA_CSTATE_WAITCLOSE;
- if (sas->sas_cstate == SA_CSTATE_WAITCLOSE)
- return 0;
-
- /* We might be able to bundle, but if we fail we'd have to reorganise */
- packetid = agentx_indexdeallocate(sa->sa_ax, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), &(sai->sai_vb), 1);
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_INDEXDEALLOCATE));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "index %s: deallocating",
- agentx_oid2string(&(sai->sai_vb.avb_oid)));
- return subagentx_request(sa, packetid, subagentx_index_close_finalize,
- sai);
-}
-
-static int
-subagentx_index_close_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_index *sai = cookie;
- struct subagentx_region *sar = sai->sai_sar;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct agentx_pdu_response *resp = &(pdu->ap_payload.ap_response);
-
-#ifdef AGENTX_DEBUG
- if (sai->sai_cstate != SA_CSTATE_WAITCLOSE)
- subagentx_log_sac_fatalx(sac, "%s: unexpected indexdeallocate",
- __func__);
-#endif
-
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- subagentx_log_sac_warnx(sac,
- "index %s: couldn't deallocate: %s",
- agentx_oid2string(&(sai->sai_vb.avb_oid)),
- agentx_error2string(resp->ap_error));
- subagentx_reset(sa);
- return -1;
- }
-
- if (resp->ap_nvarbind != 1) {
- subagentx_log_sac_warnx(sac,
- "index %s: unexpected number of indices",
- agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- if (resp->ap_varbindlist[0].avb_type != sai->sai_vb.avb_type) {
- subagentx_log_sac_warnx(sac, "index %s: unexpected index type",
- agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- if (agentx_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
- &(sai->sai_vb.avb_oid)) != 0) {
- subagentx_log_sac_warnx(sac, "index %s: unexpected oid",
- agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- switch (sai->sai_vb.avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
- if (sai->sai_vb.avb_data.avb_uint32 !=
- resp->ap_varbindlist[0].avb_data.avb_uint32) {
- subagentx_log_sac_warnx(sac,
- "index %s: unexpected index value",
- agentx_oid2string(&(sar->sar_oid)));
- subagentx_reset(sa);
- return -1;
- }
- break;
- default:
- subagentx_log_sac_fatalx(sac, "%s: Unsupported index type",
- __func__);
- }
-
- sai->sai_cstate = SA_CSTATE_CLOSE;
-
- subagentx_log_sac_info(sac, "index %s: deallocated",
- agentx_oid2string(&(sai->sai_vb.avb_oid)));
-
- if (sai->sai_dstate == SA_DSTATE_CLOSE) {
- subagentx_index_free_finalize(sai);
- } else if (sar->sar_cstate == SA_CSTATE_OPEN) {
- if (subagentx_index_start(sai) == -1)
- return -1;
- }
- return 0;
-}
-
-struct subagentx_object *
-subagentx_object(struct subagentx_region *sar, uint32_t oid[], size_t oidlen,
- struct subagentx_index *sai[], size_t sailen, int implied,
- void (*get)(struct subagentx_varbind *))
-{
- struct subagentx_object *sao, **tsao, sao_search;
- struct subagentx_index *lsai;
- int ready = 1;
- size_t i, j;
-
- if (sar->sar_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: use after free",
- __func__);
- if (oidlen < 1) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen == 0",
- __func__);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen == 0",
- __func__);
- errno = EINVAL;
- return NULL;
-#endif
- }
- if (oidlen > SUBAGENTX_OID_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: oidlen > %d",
- __func__, SUBAGENTX_OID_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
- if (sailen > SUBAGENTX_OID_INDEX_MAX_LEN) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: indexlen > %d",
- __func__, SUBAGENTX_OID_INDEX_MAX_LEN);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: indexlen > %d",
- __func__, SUBAGENTX_OID_INDEX_MAX_LEN);
- errno = EINVAL;
- return NULL;
-#endif
- }
-
- for (i = 0; i < oidlen; i++)
- sao_search.sao_oid.aoi_id[i] = oid[i];
- sao_search.sao_oid.aoi_idlen = oidlen;
-
- do {
- if (RB_FIND(sac_objects, &(sar->sar_sac->sac_objects),
- &sao_search) != NULL) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: invalid "
- "parent child object relationship", __func__);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: invalid "
- "parent child object relationship", __func__);
- errno = EINVAL;
- return NULL;
-#endif
- }
- sao_search.sao_oid.aoi_idlen--;
- } while (sao_search.sao_oid.aoi_idlen > 0);
- sao_search.sao_oid.aoi_idlen = oidlen;
- sao = RB_NFIND(sac_objects, &(sar->sar_sac->sac_objects), &sao_search);
- if (sao != NULL &&
- agentx_oid_cmp(&(sao->sao_oid), &(sao_search.sao_oid)) == 2) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: invalid parent "
- "child object relationship", __func__);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: invalid parent "
- "child object relationship", __func__);
- errno = EINVAL;
- return NULL;
-#endif
- }
- if (implied == 1) {
- lsai = sai[sailen - 1];
- if (lsai->sai_vb.avb_type == AGENTX_DATA_TYPE_OCTETSTRING) {
- if (lsai->sai_vb.avb_data.avb_ostring.aos_slen != 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac,
- "%s: implied can only be used on strings "
- "of dynamic length", __func__);
-#else
- subagentx_log_sac_warnx(sar->sar_sac,
- "%s: implied can only be used on strings "
- "of dynamic length", __func__);
- errno = EINVAL;
- return NULL;
-#endif
- }
- } else if (lsai->sai_vb.avb_type == AGENTX_DATA_TYPE_OID) {
- if (lsai->sai_vb.avb_data.avb_oid.aoi_idlen != 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac,
- "%s: implied can only be used on oids of "
- "dynamic length", __func__);
-#else
- subagentx_log_sac_warnx(sar->sar_sac,
- "%s: implied can only be used on oids of "
- "dynamic length", __func__);
- errno = EINVAL;
- return NULL;
-#endif
- }
- } else {
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sar->sar_sac, "%s: implied "
- "can only be set on oid and string indices",
- __func__);
-#else
- subagentx_log_sac_warnx(sar->sar_sac, "%s: implied can "
- "only be set on oid and string indices", __func__);
- errno = EINVAL;
- return NULL;
-#endif
- }
- }
-
- ready = sar->sar_cstate == SA_CSTATE_OPEN;
- if ((sao = calloc(1, sizeof(*sao))) == NULL)
- return NULL;
- sao->sao_sar = sar;
- bcopy(&(sao_search.sao_oid), &(sao->sao_oid), sizeof(sao->sao_oid));
- for (i = 0; i < sailen; i++) {
- sao->sao_index[i] = sai[i];
- if (sai[i]->sai_objectlen == sai[i]->sai_objectsize) {
- tsao = recallocarray(sai[i]->sai_object,
- sai[i]->sai_objectlen, sai[i]->sai_objectlen + 1,
- sizeof(*sai[i]->sai_object));
- if (tsao == NULL) {
- free(sao);
- return NULL;
- }
- sai[i]->sai_object = tsao;
- sai[i]->sai_objectsize = sai[i]->sai_objectlen + 1;
- }
- for (j = 0; j < sai[i]->sai_objectlen; j++) {
- if (agentx_oid_cmp(&(sao->sao_oid),
- &(sai[i]->sai_object[j]->sao_oid)) < 0) {
- memmove(&(sai[i]->sai_object[j + 1]),
- &(sai[i]->sai_object[j]),
- sizeof(*(sai[i]->sai_object)) *
- (sai[i]->sai_objectlen - j));
- break;
- }
- }
- sai[i]->sai_object[j] = sao;
- sai[i]->sai_objectlen++;
- if (sai[i]->sai_cstate != SA_CSTATE_OPEN)
- ready = 0;
- }
- sao->sao_indexlen = sailen;
- sao->sao_implied = implied;
- sao->sao_timeout = 0;
- sao->sao_lock = 0;
- sao->sao_get = get;
- sao->sao_cstate = SA_CSTATE_CLOSE;
- sao->sao_dstate = SA_DSTATE_OPEN;
-
- TAILQ_INSERT_TAIL(&(sar->sar_objects), sao, sao_sar_objects);
- RB_INSERT(sac_objects, &(sar->sar_sac->sac_objects), sao);
-
- if (ready)
- subagentx_object_start(sao);
-
- return sao;
-}
-
-static int
-subagentx_object_start(struct subagentx_object *sao)
-{
- struct subagentx_region *sar = sao->sao_sar;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct agentx_oid oid;
- char oids[1024];
- size_t i;
- int needregister = 0;
- uint32_t packetid;
- uint8_t flags = AGENTX_PDU_FLAG_INSTANCE_REGISTRATION;
-
-#ifdef AGENTX_DEBUG
- if (sar->sar_cstate != SA_CSTATE_OPEN ||
- sao->sao_cstate != SA_CSTATE_CLOSE ||
- sao->sao_dstate != SA_DSTATE_OPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: unexpected object registration", __func__);
-#endif
-
- if (sao->sao_timeout != 0)
- needregister = 1;
- for (i = 0; i < sao->sao_indexlen; i++) {
- if (sao->sao_index[i]->sai_cstate != SA_CSTATE_OPEN)
- return 0;
- if (sao->sao_index[i]->sai_type != SAI_TYPE_DYNAMIC)
- needregister = 1;
- }
- if (!needregister) {
- sao->sao_cstate = SA_CSTATE_WAITOPEN;
- subagentx_object_finalize(NULL, sao);
- return 0;
- }
-
- bcopy(&(sao->sao_oid), &(oid), sizeof(oid));
- for (i = 0; i < sao->sao_indexlen; i++) {
- if (sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC) {
- flags = 0;
- break;
- }
-#ifdef AGENTX_DEBUG
- if (sao->sao_index[i]->sai_vb.avb_type !=
- AGENTX_DATA_TYPE_INTEGER)
- subagentx_log_sac_fatalx(sac,
- "%s: Unsupported allocated index type", __func__);
-#endif
- oid.aoi_id[oid.aoi_idlen++] =
- sao->sao_index[i]->sai_vb.avb_data.avb_uint32;
- }
- packetid = agentx_register(sa->sa_ax, flags, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), sao->sao_timeout,
- AGENTX_PRIORITY_DEFAULT, 0, &oid, 0);
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_REGISTER));
- subagentx_reset(sa);
- return -1;
- }
- strlcpy(oids, agentx_oid2string(&(sao->sao_oid)), sizeof(oids));
- subagentx_log_sac_info(sac, "object %s (%s %s): opening",
- oids, flags ? "instance" : "region", agentx_oid2string(&(oid)));
- sao->sao_cstate = SA_CSTATE_WAITOPEN;
- return subagentx_request(sa, packetid, subagentx_object_finalize, sao);
-}
-
-static int
-subagentx_object_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_object *sao = cookie;
- struct subagentx_context *sac = sao->sao_sar->sar_sac;
- struct agentx_oid oid;
- char oids[1024];
- size_t i;
- uint8_t flags = 1;
-
-#ifdef AGENTX_DEBUG
- if (sao->sao_cstate != SA_CSTATE_WAITOPEN)
- subagentx_log_sac_fatalx(sac, "%s: not expecting object open",
- __func__);
-#endif
-
- if (pdu == NULL) {
- sao->sao_cstate = SA_CSTATE_OPEN;
- return 0;
- }
-
- bcopy(&(sao->sao_oid), &oid, sizeof(oid));
- for (i = 0; i < sao->sao_indexlen; i++) {
- if (sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC) {
- flags = 0;
- break;
- }
-#ifdef AGENTX_DEBUG
- if (sao->sao_index[i]->sai_vb.avb_type !=
- AGENTX_DATA_TYPE_INTEGER)
- subagentx_log_sac_fatalx(sac,
- "%s: Unsupported allocated index type", __func__);
-#endif
-
- oid.aoi_id[oid.aoi_idlen++] =
- sao->sao_index[i]->sai_vb.avb_data.avb_uint32;
- }
- strlcpy(oids, agentx_oid2string(&(sao->sao_oid)), sizeof(oids));
-
- /*
- * We should only be here for table objects with registered indices.
- * If we fail here something is misconfigured and the admin should fix
- * it.
- */
- if (pdu->ap_payload.ap_response.ap_error != AGENTX_PDU_ERROR_NOERROR) {
- sao->sao_cstate = SA_CSTATE_CLOSE;
- subagentx_log_sac_info(sac, "object %s (%s %s): %s",
- oids, flags ? "instance" : "region", agentx_oid2string(&oid),
- agentx_error2string(pdu->ap_payload.ap_response.ap_error));
- if (sao->sao_dstate == SA_DSTATE_CLOSE)
- return subagentx_object_close_finalize(NULL, sao);
- return 0;
- }
- sao->sao_cstate = SA_CSTATE_OPEN;
- subagentx_log_sac_info(sac, "object %s (%s %s): open", oids,
- flags ? "instance" : "region", agentx_oid2string(&oid));
-
- if (sao->sao_dstate == SA_DSTATE_CLOSE)
- return subagentx_object_close(sao);
-
- return 0;
-}
-
-static int
-subagentx_object_lock(struct subagentx_object *sao)
-{
- if (sao->sao_lock == UINT32_MAX) {
- subagentx_log_sac_warnx(sao->sao_sar->sar_sac,
- "%s: sao_lock == %u", __func__, UINT32_MAX);
- return -1;
- }
- sao->sao_lock++;
- return 0;
-}
-
-static void
-subagentx_object_unlock(struct subagentx_object *sao)
-{
-#ifdef AGENTX_DEBUG
- if (sao->sao_lock == 0)
- subagentx_log_sac_fatalx(sao->sao_sar->sar_sac,
- "%s: sao_lock == 0", __func__);
-#endif
- sao->sao_lock--;
- if (sao->sao_lock == 0 && sao->sao_dstate == SA_DSTATE_CLOSE &&
- sao->sao_cstate == SA_CSTATE_CLOSE)
- subagentx_object_free_finalize(sao);
-}
-
-static int
-subagentx_object_close(struct subagentx_object *sao)
-{
- struct subagentx_context *sac = sao->sao_sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct agentx_oid oid;
- char oids[1024];
- size_t i;
- int needclose = 0;
- uint32_t packetid;
- uint8_t flags = 1;
-
-#ifdef AGENTX_DEBUG
- if (sao->sao_cstate != SA_CSTATE_OPEN)
- subagentx_log_sac_fatalx(sac, "%s: unexpected object close",
- __func__);
-#endif
-
- for (i = 0; i < sao->sao_indexlen; i++) {
-#ifdef AGENTX_DEBUG
- if (sao->sao_index[i]->sai_cstate != SA_CSTATE_OPEN)
- subagentx_log_sac_fatalx(sac,
- "%s: Object open while index closed", __func__);
-#endif
- if (sao->sao_index[i]->sai_type != SAI_TYPE_DYNAMIC)
- needclose = 1;
- }
- sao->sao_cstate = SA_CSTATE_WAITCLOSE;
- if (sas->sas_cstate == SA_CSTATE_WAITCLOSE)
- return 0;
- if (!needclose) {
- subagentx_object_close_finalize(NULL, sao);
- return 0;
- }
-
- bcopy(&(sao->sao_oid), &(oid), sizeof(oid));
- for (i = 0; i < sao->sao_indexlen; i++) {
- if (sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC) {
- flags = 0;
- break;
- }
-#ifdef AGENTX_DEBUG
- if (sao->sao_index[i]->sai_vb.avb_type !=
- AGENTX_DATA_TYPE_INTEGER)
- subagentx_log_sac_fatalx(sac,
- "%s: Unsupported allocated index type", __func__);
-#endif
- oid.aoi_id[oid.aoi_idlen++] =
- sao->sao_index[i]->sai_vb.avb_data.avb_uint32;
- }
- packetid = agentx_unregister(sa->sa_ax, sas->sas_id,
- SUBAGENTX_CONTEXT_CTX(sac), AGENTX_PRIORITY_DEFAULT, 0, &oid, 0);
- if (packetid == 0) {
- subagentx_log_sac_warn(sac, "couldn't generate %s",
- agentx_pdutype2string(AGENTX_PDU_TYPE_UNREGISTER));
- subagentx_reset(sa);
- return -1;
- }
- strlcpy(oids, agentx_oid2string(&(sao->sao_oid)), sizeof(oids));
- subagentx_log_sac_info(sac, "object %s (%s %s): closing",
- oids, flags ? "instance" : "region", agentx_oid2string(&(oid)));
- return subagentx_request(sa, packetid, subagentx_object_close_finalize,
- sao);
-}
-
-static int
-subagentx_object_close_finalize(struct agentx_pdu *pdu, void *cookie)
-{
- struct subagentx_object *sao = cookie;
- struct subagentx_region *sar = sao->sao_sar;
- struct subagentx_context *sac = sar->sar_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct agentx_oid oid;
- char oids[1024];
- uint8_t flags = 1;
- size_t i;
-
-#ifdef AGENTX_DEBUG
- if (sao->sao_cstate != SA_CSTATE_WAITCLOSE)
- subagentx_log_sac_fatalx(sac,
- "%s: unexpected object unregister", __func__);
-#endif
-
- if (pdu != NULL) {
- bcopy(&(sao->sao_oid), &(oid), sizeof(oid));
- for (i = 0; i < sao->sao_indexlen; i++) {
- if (sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC) {
- flags = 0;
- break;
- }
-#ifdef AGENTX_DEBUG
- if (sao->sao_index[i]->sai_vb.avb_type !=
- AGENTX_DATA_TYPE_INTEGER)
- subagentx_log_sac_fatalx(sac,
- "%s: Unsupported allocated index type",
- __func__);
-#endif
- oid.aoi_id[oid.aoi_idlen++] =
- sao->sao_index[i]->sai_vb.avb_data.avb_uint32;
- }
- strlcpy(oids, agentx_oid2string(&(sao->sao_oid)), sizeof(oids));
- if (pdu->ap_payload.ap_response.ap_error !=
- AGENTX_PDU_ERROR_NOERROR) {
- subagentx_log_sac_warnx(sac,
- "closing object %s (%s %s): %s", oids,
- flags ? "instance" : "region",
- agentx_oid2string(&oid), agentx_error2string(
- pdu->ap_payload.ap_response.ap_error));
- subagentx_reset(sa);
- return -1;
- }
- subagentx_log_sac_info(sac, "object %s (%s %s): closed", oids,
- flags ? "instance" : "region", agentx_oid2string(&oid));
- }
-
- if (sao->sao_dstate == SA_DSTATE_CLOSE)
- subagentx_object_free_finalize(sao);
- else {
- if (sar->sar_cstate == SA_CSTATE_OPEN)
- if (subagentx_object_start(sao) == -1)
- return -1;
- }
-
- return 0;
-}
-
-void
-subagentx_object_free(struct subagentx_object *sao)
-{
- if (sao == NULL)
- return;
-
- if (sao->sao_dstate == SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sao->sao_sar->sar_sac,
- "%s: double free", __func__);
-
- sao->sao_dstate = SA_DSTATE_CLOSE;
-
- if (sao->sao_cstate == SA_CSTATE_OPEN) {
- if (subagentx_object_close(sao) == -1)
- return;
- }
- if (sao->sao_cstate == SA_CSTATE_CLOSE)
- subagentx_object_free_finalize(sao);
-}
-
-static void
-subagentx_object_free_finalize(struct subagentx_object *sao)
-{
-#ifdef AGENTX_DEBUG
- struct subagentx *sa = sao->sao_sar->sar_sac->sac_sas->sas_sa;
-#endif
- size_t i, j;
- int found;
-
-#ifdef AGENTX_DEBUG
- if (sao->sao_dstate != SA_DSTATE_CLOSE)
- subagentx_log_sac_fatalx(sao->sao_sar->sar_sac,
- "%s: unexpected free", __func__);
-#endif
-
- if (sao->sao_lock != 0) {
-#ifdef AGENTX_DEBUG
- if (TAILQ_EMPTY(&(sa->sa_getreqs)))
- subagentx_log_sac_fatalx(sao->sao_sar->sar_sac,
- "%s: %s sao_lock == %u", __func__,
- agentx_oid2string(&(sao->sao_oid)), sao->sao_lock);
-#endif
- return;
- }
-
- RB_REMOVE(sac_objects, &(sao->sao_sar->sar_sac->sac_objects), sao);
- TAILQ_REMOVE(&(sao->sao_sar->sar_objects), sao, sao_sar_objects);
-
- for (i = 0; i < sao->sao_indexlen; i++) {
- found = 0;
- for (j = 0; j < sao->sao_index[i]->sai_objectlen; j++) {
- if (sao->sao_index[i]->sai_object[j] == sao)
- found = 1;
- if (found && j + 1 != sao->sao_index[i]->sai_objectlen)
- sao->sao_index[i]->sai_object[j] =
- sao->sao_index[i]->sai_object[j + 1];
- }
-#ifdef AGENTX_DEBUG
- if (!found)
- subagentx_log_sac_fatalx(sao->sao_sar->sar_sac,
- "%s: object not found in index", __func__);
-#endif
- sao->sao_index[i]->sai_objectlen--;
- if (sao->sao_index[i]->sai_dstate == SA_DSTATE_CLOSE &&
- sao->sao_index[i]->sai_cstate == SA_CSTATE_CLOSE)
- subagentx_index_free_finalize(sao->sao_index[i]);
- }
-
- free(sao);
-}
-
-static void
-subagentx_object_reset(struct subagentx_object *sao)
-{
- sao->sao_cstate = SA_CSTATE_CLOSE;
-
- if (sao->sao_dstate == SA_DSTATE_CLOSE)
- subagentx_object_free_finalize(sao);
-}
-
-static int
-subagentx_object_cmp(struct subagentx_object *o1, struct subagentx_object *o2)
-{
- return agentx_oid_cmp(&(o1->sao_oid), &(o2->sao_oid));
-}
-
-static int
-subagentx_object_implied(struct subagentx_object *sao,
- struct subagentx_index *sai)
-{
- size_t i = 0;
-
- for (i = 0; i < sao->sao_indexlen; i++) {
- if (sao->sao_index[i] == sai) {
- if (sai->sai_vb.avb_data.avb_ostring.aos_slen != 0)
- return 1;
- else if (i == sao->sao_indexlen - 1)
- return sao->sao_implied;
- return 0;
- }
- }
-#ifdef AGENTX_DEBUG
- subagentx_log_sac_fatalx(sao->sao_sar->sar_sac, "%s: unsupported index",
- __func__);
-#endif
- return 0;
-}
-
-static void
-subagentx_get_start(struct subagentx_context *sac, struct agentx_pdu *pdu)
-{
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- struct subagentx_get *sag, tsag;
- struct agentx_pdu_searchrangelist *srl;
- char *logmsg = NULL;
- size_t i, j;
- int fail = 0;
-
- if ((sag = calloc(1, sizeof(*sag))) == NULL) {
- tsag.sag_sessionid = pdu->ap_header.aph_sessionid;
- tsag.sag_transactionid = pdu->ap_header.aph_transactionid;
- tsag.sag_packetid = pdu->ap_header.aph_packetid;
- tsag.sag_context_default = sac->sac_name_default;
- tsag.sag_fd = sac->sac_sas->sas_sa->sa_fd;
- subagentx_log_sag_warn(&tsag, "Couldn't parse request");
- subagentx_reset(sa);
- return;
- }
-
- sag->sag_sessionid = pdu->ap_header.aph_sessionid;
- sag->sag_transactionid = pdu->ap_header.aph_transactionid;
- sag->sag_packetid = pdu->ap_header.aph_packetid;
- sag->sag_context_default = sac->sac_name_default;
- sag->sag_fd = sac->sac_sas->sas_sa->sa_fd;
- if (!sac->sac_name_default) {
- sag->sag_context.aos_string =
- (unsigned char *)strdup((char *)sac->sac_name.aos_string);
- if (sag->sag_context.aos_string == NULL) {
- subagentx_log_sag_warn(sag, "Couldn't parse request");
- free(sag);
- subagentx_reset(sa);
- return;
- }
- }
- sag->sag_context.aos_slen = sac->sac_name.aos_slen;
- sag->sag_type = pdu->ap_header.aph_type;
- sag->sag_sac = sac;
- TAILQ_INSERT_TAIL(&(sa->sa_getreqs), sag, sag_sa_getreqs);
- if (sag->sag_type == AGENTX_PDU_TYPE_GET ||
- sag->sag_type == AGENTX_PDU_TYPE_GETNEXT) {
- srl = &(pdu->ap_payload.ap_srl);
- sag->sag_nvarbind = srl->ap_nsr;
- } else {
- sag->sag_nonrep = pdu->ap_payload.ap_getbulk.ap_nonrep;
- sag->sag_maxrep = pdu->ap_payload.ap_getbulk.ap_maxrep;
- srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
- sag->sag_nvarbind = ((srl->ap_nsr - sag->sag_nonrep) *
- sag->sag_maxrep) + sag->sag_nonrep;
- }
-
- if ((sag->sag_varbind = calloc(sag->sag_nvarbind,
- sizeof(*(sag->sag_varbind)))) == NULL) {
- subagentx_log_sag_warn(sag, "Couldn't parse request");
- subagentx_get_free(sag);
- subagentx_reset(sa);
- return;
- }
-
- /* XXX net-snmp doesn't use getbulk, so untested */
- /* Two loops: varbind after needs to be initialized */
- for (i = 0; i < srl->ap_nsr; i++) {
- if (i < sag->sag_nonrep ||
- sag->sag_type != AGENTX_PDU_TYPE_GETBULK)
- j = i;
- else if (sag->sag_maxrep == 0)
- break;
- else
- j = (sag->sag_maxrep * i) + sag->sag_nonrep;
- bcopy(&(srl->ap_sr[i].asr_start),
- &(sag->sag_varbind[j].sav_vb.avb_oid),
- sizeof(srl->ap_sr[i].asr_start));
- bcopy(&(srl->ap_sr[i].asr_start),
- &(sag->sag_varbind[j].sav_start),
- sizeof(srl->ap_sr[i].asr_start));
- bcopy(&(srl->ap_sr[i].asr_stop),
- &(sag->sag_varbind[j].sav_end),
- sizeof(srl->ap_sr[i].asr_stop));
- sag->sag_varbind[j].sav_initialized = 1;
- sag->sag_varbind[j].sav_sag = sag;
- sag->sag_varbind[j].sav_include =
- srl->ap_sr[i].asr_start.aoi_include;
- if (j == 0)
- fail |= subagentx_strcat(&logmsg, " {");
- else
- fail |= subagentx_strcat(&logmsg, ",{");
- fail |= subagentx_strcat(&logmsg,
- agentx_oid2string(&(srl->ap_sr[i].asr_start)));
- if (srl->ap_sr[i].asr_start.aoi_include)
- fail |= subagentx_strcat(&logmsg, " (inclusive)");
- if (srl->ap_sr[i].asr_stop.aoi_idlen != 0) {
- fail |= subagentx_strcat(&logmsg, " - ");
- fail |= subagentx_strcat(&logmsg,
- agentx_oid2string(&(srl->ap_sr[i].asr_stop)));
- }
- fail |= subagentx_strcat(&logmsg, "}");
- if (fail) {
- subagentx_log_sag_warn(sag, "Couldn't parse request");
- free(logmsg);
- subagentx_get_free(sag);
- subagentx_reset(sa);
- return;
- }
- }
-
- subagentx_log_sag_debug(sag, "%s:%s",
- agentx_pdutype2string(sag->sag_type), logmsg);
- free(logmsg);
-
- for (i = 0; i < srl->ap_nsr; i++) {
- if (i < sag->sag_nonrep ||
- sag->sag_type != AGENTX_PDU_TYPE_GETBULK)
- j = i;
- else if (sag->sag_maxrep == 0)
- break;
- else
- j = (sag->sag_maxrep * i) + sag->sag_nonrep;
- subagentx_varbind_start(&(sag->sag_varbind[j]));
- }
-}
-
-static void
-subagentx_get_finalize(struct subagentx_get *sag)
-{
- struct subagentx_context *sac = sag->sag_sac;
- struct subagentx_session *sas = sac->sac_sas;
- struct subagentx *sa = sas->sas_sa;
- size_t i, j, nvarbind = 0;
- uint16_t error = 0, index = 0;
- struct agentx_varbind *vbl;
- char *logmsg = NULL;
- int fail = 0;
-
- for (i = 0; i < sag->sag_nvarbind; i++) {
- if (sag->sag_varbind[i].sav_initialized) {
- if (sag->sag_varbind[i].sav_vb.avb_type == 0)
- return;
- nvarbind++;
- }
- }
-
- if (sag->sag_sac == NULL) {
- subagentx_get_free(sag);
- return;
- }
-
- if ((vbl = calloc(nvarbind, sizeof(*vbl))) == NULL) {
- subagentx_log_sag_warn(sag, "Couldn't parse request");
- subagentx_get_free(sag);
- subagentx_reset(sa);
- return;
- }
- for (i = 0, j = 0; i < sag->sag_nvarbind; i++) {
- if (sag->sag_varbind[i].sav_initialized) {
- memcpy(&(vbl[j]), &(sag->sag_varbind[i].sav_vb),
- sizeof(*vbl));
- if (error == 0 && sag->sag_varbind[i].sav_error !=
- AGENTX_PDU_ERROR_NOERROR) {
- error = sag->sag_varbind[i].sav_error;
- index = j + 1;
- }
- if (j == 0)
- fail |= subagentx_strcat(&logmsg, " {");
- else
- fail |= subagentx_strcat(&logmsg, ",{");
- fail |= subagentx_strcat(&logmsg,
- agentx_varbind2string(&(vbl[j])));
- if (sag->sag_varbind[i].sav_error !=
- AGENTX_PDU_ERROR_NOERROR) {
- fail |= subagentx_strcat(&logmsg, "(");
- fail |= subagentx_strcat(&logmsg,
- agentx_error2string(
- sag->sag_varbind[i].sav_error));
- fail |= subagentx_strcat(&logmsg, ")");
- }
- fail |= subagentx_strcat(&logmsg, "}");
- if (fail) {
- subagentx_log_sag_warn(sag,
- "Couldn't parse request");
- free(logmsg);
- subagentx_get_free(sag);
- return;
- }
- j++;
- }
- }
- subagentx_log_sag_debug(sag, "response:%s", logmsg);
- free(logmsg);
-
- if (agentx_response(sa->sa_ax, sas->sas_id, sag->sag_transactionid,
- sag->sag_packetid, SUBAGENTX_CONTEXT_CTX(sac), 0, error, index,
- vbl, nvarbind) == -1) {
- subagentx_log_sag_warn(sag, "Couldn't parse request");
- subagentx_reset(sa);
- } else
- subagentx_wantwrite(sa, sa->sa_fd);
- free(vbl);
- subagentx_get_free(sag);
-}
-
-void
-subagentx_get_free(struct subagentx_get *sag)
-{
- struct subagentx_varbind *sav;
- struct subagentx_object *sao;
- struct subagentx *sa = sag->sag_sac->sac_sas->sas_sa;
- struct subagentx_varbind_index *index;
- size_t i, j;
-
- if (sag->sag_sac != NULL)
- TAILQ_REMOVE(&(sa->sa_getreqs), sag, sag_sa_getreqs);
-
- for (i = 0; i < sag->sag_nvarbind; i++) {
- sav = &(sag->sag_varbind[i]);
- for (j = 0; sav->sav_sao != NULL &&
- j < sav->sav_sao->sao_indexlen; j++) {
- sao = sav->sav_sao;
- index = &(sav->sav_index[j]);
- if (sao->sao_index[j]->sai_vb.avb_type ==
- AGENTX_DATA_TYPE_OCTETSTRING ||
- sao->sao_index[j]->sai_vb.avb_type ==
- AGENTX_DATA_TYPE_IPADDRESS)
- free(index->sav_idata.avb_ostring.aos_string);
- }
- agentx_varbind_free(&(sag->sag_varbind[i].sav_vb));
- }
-
- free(sag->sag_context.aos_string);
- free(sag->sag_varbind);
- free(sag);
-}
-
-static void
-subagentx_varbind_start(struct subagentx_varbind *sav)
-{
- struct subagentx_get *sag = sav->sav_sag;
- struct subagentx_context *sac = sag->sag_sac;
- struct subagentx_object *sao, sao_search;
- struct subagentx_varbind_index *index;
- struct subagentx_index *sai;
- struct agentx_oid *oid;
- union agentx_data *data;
- struct in_addr *ipaddress;
- unsigned char *ipbytes;
- size_t i, j, k;
- int overflow = 0, dynamic;
-
-#ifdef AGENTX_DEBUG
- if (!sav->sav_initialized)
- subagentx_log_sag_fatalx(sav->sav_sag,
- "%s: sav_initialized not set", __func__);
-#endif
-
- bcopy(&(sav->sav_vb.avb_oid), &(sao_search.sao_oid),
- sizeof(sao_search.sao_oid));
-
- do {
- sao = RB_FIND(sac_objects, &(sac->sac_objects), &sao_search);
- if (sao_search.sao_oid.aoi_idlen > 0)
- sao_search.sao_oid.aoi_idlen--;
- } while (sao == NULL && sao_search.sao_oid.aoi_idlen > 0);
- if (sao == NULL || sao->sao_cstate != SA_CSTATE_OPEN) {
- sav->sav_include = 1;
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET) {
- subagentx_varbind_nosuchobject(sav);
- return;
- }
- bcopy(&(sav->sav_vb.avb_oid), &(sao_search.sao_oid),
- sizeof(sao_search.sao_oid));
- sao = RB_NFIND(sac_objects, &(sac->sac_objects), &sao_search);
-getnext:
- while (sao != NULL && sao->sao_cstate != SA_CSTATE_OPEN)
- sao = RB_NEXT(sac_objects, &(sac->sac_objects), sao);
- if (sao == NULL) {
- subagentx_varbind_endofmibview(sav);
- return;
- }
- bcopy(&(sao->sao_oid), &(sav->sav_vb.avb_oid),
- sizeof(sao->sao_oid));
- }
- sav->sav_sao = sao;
- sav->sav_indexlen = sao->sao_indexlen;
- if (subagentx_object_lock(sao) == -1) {
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
-
- oid = &(sav->sav_vb.avb_oid);
- if (sao->sao_indexlen == 0) {
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET) {
- if (oid->aoi_idlen != sao->sao_oid.aoi_idlen + 1 ||
- oid->aoi_id[oid->aoi_idlen - 1] != 0) {
- subagentx_varbind_nosuchinstance(sav);
- return;
- }
- } else {
- if (oid->aoi_idlen == sao->sao_oid.aoi_idlen) {
- oid->aoi_id[oid->aoi_idlen++] = 0;
- sav->sav_include = 1;
- } else {
- sav->sav_sao = NULL;
- subagentx_object_unlock(sao);
- sao = RB_NEXT(sac_objects, &(sac->sac_objects),
- sao);
- goto getnext;
- }
- }
- }
- j = sao->sao_oid.aoi_idlen;
-/*
- * We can't trust what the client gives us, so sometimes we need to map it to
- * index type.
- * - AGENTX_PDU_TYPE_GET: we always return AGENTX_DATA_TYPE_NOSUCHINSTANCE
- * - AGENTX_PDU_TYPE_GETNEXT:
- * - Missing OID digits to match indices will result in the indices to be NUL-
- * initialized and the request type will be set to
- * SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
- * - An overflow can happen on AGENTX_DATA_TYPE_OCTETSTRING and
- * AGENTX_DATA_TYPE_IPADDRESS. This results in request type being set to
- * SUBAGENTX_REQUEST_TYPE_GETNEXT and will set the index to its maximum
- * value:
- * - AGENTX_DATA_TYPE_INTEGER: UINT32_MAX
- * - AGENTX_DATA_TYPE_OCTETSTRING: aos_slen = UINT32_MAX and
- * aos_string = NULL
- * - AGENTX_DATA_TYPE_OID: aoi_idlen = UINT32_MAX and aoi_id[x] = UINT32_MAX
- * - AGENTX_DATA_TYPE_IPADDRESS: 255.255.255.255
- */
- for (dynamic = 0, i = 0; i < sao->sao_indexlen; i++) {
- index = &(sav->sav_index[i]);
- index->sav_sai = sao->sao_index[i];
- data = &(index->sav_idata);
- if (sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC)
- dynamic = 1;
- if (j >= sav->sav_vb.avb_oid.aoi_idlen && !overflow &&
- sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC)
- continue;
- switch (sao->sao_index[i]->sai_vb.avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
-/* Dynamic index: normal copy paste */
- if (sao->sao_index[i]->sai_type == SAI_TYPE_DYNAMIC) {
- data->avb_uint32 = overflow ?
- UINT32_MAX : sav->sav_vb.avb_oid.aoi_id[j];
- j++;
- index->sav_idatacomplete = 1;
- break;
- }
- sai = sao->sao_index[i];
-/* With a GET-request we need an exact match */
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET) {
- if (sai->sai_vb.avb_data.avb_uint32 !=
- sav->sav_vb.avb_oid.aoi_id[j]) {
- subagentx_varbind_nosuchinstance(sav);
- return;
- }
- index->sav_idatacomplete = 1;
- j++;
- break;
- }
-/* A higher value automatically moves us to the next value */
- if (overflow ||
- sav->sav_vb.avb_oid.aoi_id[j] >
- sai->sai_vb.avb_data.avb_uint32) {
-/* If we're !dynamic up until now the rest of the oid doesn't matter */
- if (!dynamic) {
- subagentx_varbind_endofmibview(sav);
- return;
- }
-/*
- * Else we just pick the max value and make sure we don't return
- * SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
- */
- data->avb_uint32 = UINT32_MAX;
- index->sav_idatacomplete = 1;
- overflow = 1;
- j++;
- break;
-/*
- * A lower value automatically moves to the set value and counts as a short oid
- */
- } else if (sav->sav_vb.avb_oid.aoi_id[j] <
- sai->sai_vb.avb_data.avb_uint32) {
- data->avb_uint32 =
- sai->sai_vb.avb_data.avb_uint32;
- j = sav->sav_vb.avb_oid.aoi_idlen;
- break;
- }
-/* Normal match, except we already matched overflow at higher value */
- data->avb_uint32 = sav->sav_vb.avb_oid.aoi_id[j];
- j++;
- index->sav_idatacomplete = 1;
- break;
- case AGENTX_DATA_TYPE_OCTETSTRING:
- if (!subagentx_object_implied(sao, index->sav_sai)) {
- if (overflow || sav->sav_vb.avb_oid.aoi_id[j] >
- SUBAGENTX_OID_MAX_LEN -
- sav->sav_vb.avb_oid.aoi_idlen) {
- overflow = 1;
- data->avb_ostring.aos_slen = UINT32_MAX;
- index->sav_idatacomplete = 1;
- continue;
- }
- data->avb_ostring.aos_slen =
- sav->sav_vb.avb_oid.aoi_id[j++];
- } else {
- if (overflow) {
- data->avb_ostring.aos_slen = UINT32_MAX;
- index->sav_idatacomplete = 1;
- continue;
- }
- data->avb_ostring.aos_slen =
- sav->sav_vb.avb_oid.aoi_idlen - j;
- }
- data->avb_ostring.aos_string =
- calloc(data->avb_ostring.aos_slen + 1, 1);
- if (data->avb_ostring.aos_string == NULL) {
- subagentx_log_sag_warn(sag,
- "Failed to bind string index");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
- for (k = 0; k < data->avb_ostring.aos_slen; k++, j++) {
- if (!overflow &&
- j == sav->sav_vb.avb_oid.aoi_idlen)
- break;
-
- if (sav->sav_vb.avb_oid.aoi_id[j] > 255)
- overflow = 1;
-
- data->avb_ostring.aos_string[k] = overflow ?
- 0xff : sav->sav_vb.avb_oid.aoi_id[j];
- }
- if (k == data->avb_ostring.aos_slen)
- index->sav_idatacomplete = 1;
- break;
- case AGENTX_DATA_TYPE_OID:
- if (!subagentx_object_implied(sao, index->sav_sai)) {
- if (overflow || sav->sav_vb.avb_oid.aoi_id[j] >
- SUBAGENTX_OID_MAX_LEN -
- sav->sav_vb.avb_oid.aoi_idlen) {
- overflow = 1;
- data->avb_oid.aoi_idlen = UINT32_MAX;
- index->sav_idatacomplete = 1;
- continue;
- }
- data->avb_oid.aoi_idlen =
- sav->sav_vb.avb_oid.aoi_id[j++];
- } else {
- if (overflow) {
- data->avb_oid.aoi_idlen = UINT32_MAX;
- index->sav_idatacomplete = 1;
- continue;
- }
- data->avb_oid.aoi_idlen =
- sav->sav_vb.avb_oid.aoi_idlen - j;
- }
- for (k = 0; k < data->avb_oid.aoi_idlen; k++, j++) {
- if (!overflow &&
- j == sav->sav_vb.avb_oid.aoi_idlen) {
- data->avb_oid.aoi_id[k] = 0;
- continue;
- }
- data->avb_oid.aoi_id[k] = overflow ?
- UINT32_MAX : sav->sav_vb.avb_oid.aoi_id[j];
- }
- if (j <= sav->sav_vb.avb_oid.aoi_idlen)
- index->sav_idatacomplete = 1;
- break;
- case AGENTX_DATA_TYPE_IPADDRESS:
- ipaddress = calloc(1, sizeof(*ipaddress));
- if (ipaddress == NULL) {
- subagentx_log_sag_warn(sag,
- "Failed to bind ipaddress index");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
- ipbytes = (unsigned char *)ipaddress;
- for (k = 0; k < 4; k++, j++) {
- if (!overflow &&
- j == sav->sav_vb.avb_oid.aoi_idlen)
- break;
-
- if (sav->sav_vb.avb_oid.aoi_id[j] > 255)
- overflow = 1;
-
- ipbytes[k] = overflow ? 255 :
- sav->sav_vb.avb_oid.aoi_id[j];
- }
- if (j <= sav->sav_vb.avb_oid.aoi_idlen)
- index->sav_idatacomplete = 1;
- data->avb_ostring.aos_slen = sizeof(*ipaddress);
- data->avb_ostring.aos_string =
- (unsigned char *)ipaddress;
- break;
- default:
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sag,
- "%s: unexpected index type", __func__);
-#else
- subagentx_log_sag_warnx(sag,
- "%s: unexpected index type", __func__);
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
-#endif
- }
- }
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET) {
- if ((sao->sao_indexlen > 0 &&
- !sav->sav_index[sao->sao_indexlen - 1].sav_idatacomplete) ||
- j != sav->sav_vb.avb_oid.aoi_idlen || overflow) {
- subagentx_varbind_nosuchinstance(sav);
- return;
- }
- }
-
- if (overflow || j > sav->sav_vb.avb_oid.aoi_idlen)
- sav->sav_include = 0;
-
-/*
- * SUBAGENTX_REQUEST_TYPE_GETNEXT request can !dynamic objects can just move to
- * the next object
- */
- if (subagentx_varbind_request(sav) == SUBAGENTX_REQUEST_TYPE_GETNEXT &&
- !dynamic) {
- subagentx_varbind_endofmibview(sav);
- return;
- }
-
- sao->sao_get(sav);
-}
-
-void
-subagentx_varbind_integer(struct subagentx_varbind *sav, uint32_t value)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_INTEGER;
- sav->sav_vb.avb_data.avb_uint32 = value;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_string(struct subagentx_varbind *sav, const char *value)
-{
- subagentx_varbind_nstring(sav, (const unsigned char *)value,
- strlen(value));
-}
-
-void
-subagentx_varbind_nstring(struct subagentx_varbind *sav,
- const unsigned char *value, size_t slen)
-{
- sav->sav_vb.avb_data.avb_ostring.aos_string = malloc(slen);
- if (sav->sav_vb.avb_data.avb_ostring.aos_string == NULL) {
- subagentx_log_sag_warn(sav->sav_sag, "Couldn't bind string");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_OCTETSTRING;
- memcpy(sav->sav_vb.avb_data.avb_ostring.aos_string, value, slen);
- sav->sav_vb.avb_data.avb_ostring.aos_slen = slen;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_printf(struct subagentx_varbind *sav, const char *fmt, ...)
-{
- va_list ap;
- int r;
-
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_OCTETSTRING;
- va_start(ap, fmt);
- r = vasprintf((char **)&(sav->sav_vb.avb_data.avb_ostring.aos_string),
- fmt, ap);
- va_end(ap);
- if (r == -1) {
- sav->sav_vb.avb_data.avb_ostring.aos_string = NULL;
- subagentx_log_sag_warn(sav->sav_sag, "Couldn't bind string");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
- sav->sav_vb.avb_data.avb_ostring.aos_slen = r;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_null(struct subagentx_varbind *sav)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_NULL;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_oid(struct subagentx_varbind *sav, const uint32_t oid[],
- size_t oidlen)
-{
- size_t i;
-
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_OID;
-
- for (i = 0; i < oidlen; i++)
- sav->sav_vb.avb_data.avb_oid.aoi_id[i] = oid[i];
- sav->sav_vb.avb_data.avb_oid.aoi_idlen = oidlen;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_object(struct subagentx_varbind *sav,
- struct subagentx_object *sao)
-{
- subagentx_varbind_oid(sav, sao->sao_oid.aoi_id,
- sao->sao_oid.aoi_idlen);
-}
-
-void
-subagentx_varbind_index(struct subagentx_varbind *sav,
- struct subagentx_index *sai)
-{
- subagentx_varbind_oid(sav, sai->sai_vb.avb_oid.aoi_id,
- sai->sai_vb.avb_oid.aoi_idlen);
-}
-
-
-void
-subagentx_varbind_ipaddress(struct subagentx_varbind *sav,
- const struct in_addr *value)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_IPADDRESS;
- sav->sav_vb.avb_data.avb_ostring.aos_string = malloc(4);
- if (sav->sav_vb.avb_data.avb_ostring.aos_string == NULL) {
- subagentx_log_sag_warn(sav->sav_sag, "Couldn't bind ipaddress");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
- memcpy(sav->sav_vb.avb_data.avb_ostring.aos_string, value, 4);
- sav->sav_vb.avb_data.avb_ostring.aos_slen = 4;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_counter32(struct subagentx_varbind *sav, uint32_t value)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_COUNTER32;
- sav->sav_vb.avb_data.avb_uint32 = value;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_gauge32(struct subagentx_varbind *sav, uint32_t value)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_GAUGE32;
- sav->sav_vb.avb_data.avb_uint32 = value;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_timeticks(struct subagentx_varbind *sav, uint32_t value)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_TIMETICKS;
- sav->sav_vb.avb_data.avb_uint32 = value;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_opaque(struct subagentx_varbind *sav, const char *string,
- size_t strlen)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_OPAQUE;
- sav->sav_vb.avb_data.avb_ostring.aos_string = malloc(strlen);
- if (sav->sav_vb.avb_data.avb_ostring.aos_string == NULL) {
- subagentx_log_sag_warn(sav->sav_sag, "Couldn't bind opaque");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 1);
- return;
- }
- memcpy(sav->sav_vb.avb_data.avb_ostring.aos_string, string, strlen);
- sav->sav_vb.avb_data.avb_ostring.aos_slen = strlen;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_counter64(struct subagentx_varbind *sav, uint64_t value)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_COUNTER64;
- sav->sav_vb.avb_data.avb_uint64 = value;
-
- subagentx_varbind_finalize(sav);
-}
-
-void
-subagentx_varbind_notfound(struct subagentx_varbind *sav)
-{
- if (sav->sav_indexlen == 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "%s invalid call",
- __func__);
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "%s invalid call",
- __func__);
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 1);
-#endif
- } else if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET)
- subagentx_varbind_nosuchinstance(sav);
- else
- subagentx_varbind_endofmibview(sav);
-}
-
-void
-subagentx_varbind_error(struct subagentx_varbind *sav)
-{
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 1);
-}
-
-static void
-subagentx_varbind_error_type(struct subagentx_varbind *sav,
- enum agentx_pdu_error error, int done)
-{
- if (sav->sav_error == AGENTX_PDU_ERROR_NOERROR) {
- sav->sav_error = error;
- }
-
- if (done) {
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_NULL;
-
- subagentx_varbind_finalize(sav);
- }
-}
-
-static void
-subagentx_varbind_finalize(struct subagentx_varbind *sav)
-{
- struct subagentx_get *sag = sav->sav_sag;
- struct agentx_oid oid;
- union agentx_data *data;
- size_t i, j;
- int cmp;
-
- if (sav->sav_error != AGENTX_PDU_ERROR_NOERROR) {
- bcopy(&(sav->sav_start), &(sav->sav_vb.avb_oid),
- sizeof(sav->sav_start));
- goto done;
- }
- bcopy(&(sav->sav_sao->sao_oid), &oid, sizeof(oid));
- if (sav->sav_indexlen == 0)
- agentx_oid_add(&oid, 0);
- for (i = 0; i < sav->sav_indexlen; i++) {
- data = &(sav->sav_index[i].sav_idata);
- switch (sav->sav_index[i].sav_sai->sai_vb.avb_type) {
- case AGENTX_DATA_TYPE_INTEGER:
- if (agentx_oid_add(&oid, data->avb_uint32) == -1)
- goto fail;
- break;
- case AGENTX_DATA_TYPE_OCTETSTRING:
- if (!subagentx_object_implied(sav->sav_sao,
- sav->sav_index[i].sav_sai)) {
- if (agentx_oid_add(&oid,
- data->avb_ostring.aos_slen) == -1)
- goto fail;
- }
- for (j = 0; j < data->avb_ostring.aos_slen; j++) {
- if (agentx_oid_add(&oid,
- (uint8_t)data->avb_ostring.aos_string[j]) ==
- -1)
- goto fail;
- }
- break;
- case AGENTX_DATA_TYPE_OID:
- if (!subagentx_object_implied(sav->sav_sao,
- sav->sav_index[i].sav_sai)) {
- if (agentx_oid_add(&oid,
- data->avb_oid.aoi_idlen) == -1)
- goto fail;
- }
- for (j = 0; j < data->avb_oid.aoi_idlen; j++) {
- if (agentx_oid_add(&oid,
- data->avb_oid.aoi_id[j]) == -1)
- goto fail;
- }
- break;
- case AGENTX_DATA_TYPE_IPADDRESS:
- for (j = 0; j < 4; j++) {
- if (agentx_oid_add(&oid,
- data->avb_ostring.aos_string == NULL ? 0 :
- (uint8_t)data->avb_ostring.aos_string[j]) ==
- -1)
- goto fail;
- }
- break;
- default:
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sag,
- "%s: unsupported index type", __func__);
-#else
- bcopy(&(sav->sav_start), &(sav->sav_vb.avb_oid),
- sizeof(sav->sav_start));
- sav->sav_error = AGENTX_PDU_ERROR_PROCESSINGERROR;
- subagentx_object_unlock(sav->sav_sao);
- subagentx_get_finalize(sav->sav_sag);
- return;
-#endif
- }
- }
- cmp = agentx_oid_cmp(&(sav->sav_vb.avb_oid), &oid);
- if ((subagentx_varbind_request(sav) == SUBAGENTX_REQUEST_TYPE_GETNEXT &&
- cmp >= 0) || cmp > 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sag, "indices not incremented");
-#else
- subagentx_log_sag_warnx(sag, "indices not incremented");
- bcopy(&(sav->sav_start), &(sav->sav_vb.avb_oid),
- sizeof(sav->sav_start));
- sav->sav_error = AGENTX_PDU_ERROR_GENERR;
-#endif
- } else
- bcopy(&oid, &(sav->sav_vb.avb_oid), sizeof(oid));
-done:
- subagentx_object_unlock(sav->sav_sao);
- subagentx_get_finalize(sav->sav_sag);
- return;
-
-fail:
- subagentx_log_sag_warnx(sag, "oid too large");
- bcopy(&(sav->sav_start), &(sav->sav_vb.avb_oid),
- sizeof(sav->sav_start));
- sav->sav_error = AGENTX_PDU_ERROR_GENERR;
- subagentx_object_unlock(sav->sav_sao);
- subagentx_get_finalize(sav->sav_sag);
-}
-
-static void
-subagentx_varbind_nosuchobject(struct subagentx_varbind *sav)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_NOSUCHOBJECT;
-
- if (sav->sav_sao != NULL)
- subagentx_object_unlock(sav->sav_sao);
- subagentx_get_finalize(sav->sav_sag);
-}
-
-static void
-subagentx_varbind_nosuchinstance(struct subagentx_varbind *sav)
-{
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_NOSUCHINSTANCE;
-
- if (sav->sav_sao != NULL)
- subagentx_object_unlock(sav->sav_sao);
- subagentx_get_finalize(sav->sav_sag);
-}
-
-static void
-subagentx_varbind_endofmibview(struct subagentx_varbind *sav)
-{
- struct subagentx_object *sao;
- struct agentx_varbind *vb;
- struct subagentx_varbind_index *index;
- size_t i;
-
-#ifdef AGENTX_DEBUG
- if (sav->sav_sag->sag_type != AGENTX_PDU_TYPE_GETNEXT &&
- sav->sav_sag->sag_type != AGENTX_PDU_TYPE_GETBULK)
- subagentx_log_sag_fatalx(sav->sav_sag,
- "%s: invalid request type", __func__);
-#endif
-
- if (sav->sav_sao != NULL &&
- (sao = RB_NEXT(sac_objects, &(sac->sac_objects),
- sav->sav_sao)) != NULL &&
- agentx_oid_cmp(&(sao->sao_oid), &(sav->sav_end)) < 0) {
- bcopy(&(sao->sao_oid), &(sav->sav_vb.avb_oid),
- sizeof(sao->sao_oid));
- sav->sav_include = 1;
- for (i = 0; i < sav->sav_indexlen; i++) {
- index = &(sav->sav_index[i]);
- vb = &(index->sav_sai->sai_vb);
- if (vb->avb_type == AGENTX_DATA_TYPE_OCTETSTRING ||
- vb->avb_type == AGENTX_DATA_TYPE_IPADDRESS)
- free(index->sav_idata.avb_ostring.aos_string);
- }
- bzero(&(sav->sav_index), sizeof(sav->sav_index));
- subagentx_object_unlock(sav->sav_sao);
- subagentx_varbind_start(sav);
- return;
- }
-
- sav->sav_vb.avb_type = AGENTX_DATA_TYPE_ENDOFMIBVIEW;
-
- if (sav->sav_sao != NULL)
- subagentx_object_unlock(sav->sav_sao);
- subagentx_get_finalize(sav->sav_sag);
-}
-
-enum subagentx_request_type
-subagentx_varbind_request(struct subagentx_varbind *sav)
-{
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET)
- return SUBAGENTX_REQUEST_TYPE_GET;
- if (sav->sav_include ||
- (sav->sav_indexlen > 0 &&
- !sav->sav_index[sav->sav_indexlen - 1].sav_idatacomplete))
- return SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE;
- return SUBAGENTX_REQUEST_TYPE_GETNEXT;
-}
-
-struct subagentx_object *
-subagentx_varbind_get_object(struct subagentx_varbind *sav)
-{
- return sav->sav_sao;
-}
-
-uint32_t
-subagentx_varbind_get_index_integer(struct subagentx_varbind *sav,
- struct subagentx_index *sai)
-{
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_INTEGER) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return 0;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai)
- return sav->sav_index[i].sav_idata.avb_uint32;
- }
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return 0;
-#endif
-}
-
-const unsigned char *
-subagentx_varbind_get_index_string(struct subagentx_varbind *sav,
- struct subagentx_index *sai, size_t *slen, int *implied)
-{
- struct subagentx_varbind_index *index;
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_OCTETSTRING) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- *slen = 0;
- *implied = 0;
- return NULL;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- index = &(sav->sav_index[i]);
- *slen = index->sav_idata.avb_ostring.aos_slen;
- *implied = subagentx_object_implied(sav->sav_sao, sai);
- return index->sav_idata.avb_ostring.aos_string;
- }
- }
-
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- *slen = 0;
- *implied = 0;
- return NULL;
-#endif
-}
-
-const uint32_t *
-subagentx_varbind_get_index_oid(struct subagentx_varbind *sav,
- struct subagentx_index *sai, size_t *oidlen, int *implied)
-{
- struct subagentx_varbind_index *index;
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_OID) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- *oidlen = 0;
- *implied = 0;
- return NULL;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- index = &(sav->sav_index[i]);
- *oidlen = index->sav_idata.avb_oid.aoi_idlen;
- *implied = subagentx_object_implied(sav->sav_sao, sai);
- return index->sav_idata.avb_oid.aoi_id;
- }
- }
-
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- *oidlen = 0;
- *implied = 0;
- return NULL;
-#endif
-}
-
-const struct in_addr *
-subagentx_varbind_get_index_ipaddress(struct subagentx_varbind *sav,
- struct subagentx_index *sai)
-{
- static struct in_addr nuladdr = {0};
- struct subagentx_varbind_index *index;
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_IPADDRESS) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return NULL;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- index = &(sav->sav_index[i]);
- if (index->sav_idata.avb_ostring.aos_string == NULL)
- return &nuladdr;
- return (struct in_addr *)
- index->sav_idata.avb_ostring.aos_string;
- }
- }
-
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return NULL;
-#endif
-}
-
-void
-subagentx_varbind_set_index_integer(struct subagentx_varbind *sav,
- struct subagentx_index *sai, uint32_t value)
-{
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_INTEGER) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET &&
- sav->sav_index[i].sav_idata.avb_uint32 != value) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag,
- "can't change index on GET");
-#else
- subagentx_log_sag_warnx(sav->sav_sag,
- "can't change index on GET");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
- sav->sav_index[i].sav_idata.avb_uint32 = value;
- return;
- }
- }
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
-#endif
-}
-
-void
-subagentx_varbind_set_index_string(struct subagentx_varbind *sav,
- struct subagentx_index *sai, const char *value)
-{
- subagentx_varbind_set_index_nstring(sav, sai,
- (const unsigned char *)value, strlen(value));
-}
-
-void
-subagentx_varbind_set_index_nstring(struct subagentx_varbind *sav,
- struct subagentx_index *sai, const unsigned char *value, size_t slen)
-{
- struct agentx_ostring *curvalue;
- unsigned char *nstring;
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_OCTETSTRING) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- if (sai->sai_vb.avb_data.avb_ostring.aos_slen != 0 &&
- sai->sai_vb.avb_data.avb_ostring.aos_slen != slen) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag,
- "invalid string length on explicit length "
- "string");
-#else
- subagentx_log_sag_warnx(sav->sav_sag,
- "invalid string length on explicit length "
- "string");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
- curvalue = &(sav->sav_index[i].sav_idata.avb_ostring);
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET &&
- (curvalue->aos_slen != slen ||
- memcmp(curvalue->aos_string, value, slen) != 0)) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag,
- "can't change index on GET");
-#else
- subagentx_log_sag_warnx(sav->sav_sag,
- "can't change index on GET");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
- if ((nstring = recallocarray(curvalue->aos_string,
- curvalue->aos_slen + 1, slen + 1, 1)) == NULL) {
- subagentx_log_sag_warn(sav->sav_sag,
- "Failed to bind string index");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 0);
- return;
- }
- curvalue->aos_string = nstring;
- memcpy(nstring, value, slen);
- curvalue->aos_slen = slen;
- return;
- }
- }
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
-#endif
-}
-
-void
-subagentx_varbind_set_index_oid(struct subagentx_varbind *sav,
- struct subagentx_index *sai, const uint32_t *value, size_t oidlen)
-{
- struct agentx_oid *curvalue, oid;
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_OID) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- if (sai->sai_vb.avb_data.avb_oid.aoi_idlen != 0 &&
- sai->sai_vb.avb_data.avb_oid.aoi_idlen != oidlen) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag,
- "invalid oid length on explicit length "
- "oid");
-#else
- subagentx_log_sag_warnx(sav->sav_sag,
- "invalid oid length on explicit length "
- "oid");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
- curvalue = &(sav->sav_index[i].sav_idata.avb_oid);
- for (i = 0; i < oidlen; i++)
- oid.aoi_id[i] = value[i];
- oid.aoi_idlen = oidlen;
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET &&
- agentx_oid_cmp(&oid, curvalue) != 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag,
- "can't change index on GET");
-#else
- subagentx_log_sag_warnx(sav->sav_sag,
- "can't change index on GET");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
- for (i = 0; i < oidlen; i++)
- curvalue->aoi_id[i] = value[i];
- curvalue->aoi_idlen = oidlen;
- return;
- }
- }
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
-#endif
-}
-
-void
-subagentx_varbind_set_index_object(struct subagentx_varbind *sav,
- struct subagentx_index *sai, struct subagentx_object *sao)
-{
- subagentx_varbind_set_index_oid(sav, sai, sao->sao_oid.aoi_id,
- sao->sao_oid.aoi_idlen);
-}
-
-void
-subagentx_varbind_set_index_ipaddress(struct subagentx_varbind *sav,
- struct subagentx_index *sai, const struct in_addr *addr)
-{
- struct agentx_ostring *curvalue;
- size_t i;
-
- if (sai->sai_vb.avb_type != AGENTX_DATA_TYPE_IPADDRESS) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index type");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index type");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
-
- for (i = 0; i < sav->sav_indexlen; i++) {
- if (sav->sav_index[i].sav_sai == sai) {
- curvalue = &(sav->sav_index[i].sav_idata.avb_ostring);
- if (curvalue->aos_string == NULL)
- curvalue->aos_string = calloc(1, sizeof(*addr));
- if (curvalue->aos_string == NULL) {
- subagentx_log_sag_warn(sav->sav_sag,
- "Failed to bind ipaddress index");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_PROCESSINGERROR, 0);
- return;
- }
- if (sav->sav_sag->sag_type == AGENTX_PDU_TYPE_GET &&
- memcmp(addr, curvalue->aos_string,
- sizeof(*addr)) != 0) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag,
- "can't change index on GET");
-#else
- subagentx_log_sag_warnx(sav->sav_sag,
- "can't change index on GET");
- subagentx_varbind_error_type(sav,
- AGENTX_PDU_ERROR_GENERR, 0);
- return;
-#endif
- }
- bcopy(addr, curvalue->aos_string, sizeof(*addr));
- return;
- }
- }
-#ifdef AGENTX_DEBUG
- subagentx_log_sag_fatalx(sav->sav_sag, "invalid index");
-#else
- subagentx_log_sag_warnx(sav->sav_sag, "invalid index");
- subagentx_varbind_error_type(sav, AGENTX_PDU_ERROR_GENERR, 0);
-#endif
-}
-
-static int
-subagentx_request(struct subagentx *sa, uint32_t packetid,
- int (*cb)(struct agentx_pdu *, void *), void *cookie)
-{
- struct subagentx_request *sar;
-
-#ifdef AGENTX_DEBUG
- if (sa->sa_ax->ax_wblen == 0)
- subagentx_log_sa_fatalx(sa, "%s: no data to be written",
- __func__);
-#endif
-
- if ((sar = calloc(1, sizeof(*sar))) == NULL) {
- subagentx_log_sa_warn(sa, "couldn't create request context");
- subagentx_reset(sa);
- return -1;
- }
-
- sar->sar_packetid = packetid;
- sar->sar_cb = cb;
- sar->sar_cookie = cookie;
- if (RB_INSERT(sa_requests, &(sa->sa_requests), sar) != NULL) {
-#ifdef AGENTX_DEBUG
- subagentx_log_sa_fatalx(sa, "%s: duplicate packetid", __func__);
-#else
- subagentx_log_sa_warnx(sa, "%s: duplicate packetid", __func__);
- free(sar);
- subagentx_reset(sa);
- return -1;
-#endif
- }
-
- subagentx_wantwrite(sa, sa->sa_fd);
- return 0;
-}
-
-static int
-subagentx_request_cmp(struct subagentx_request *r1,
- struct subagentx_request *r2)
-{
- return r1->sar_packetid < r2->sar_packetid ? -1 :
- r1->sar_packetid > r2->sar_packetid;
-}
-
-static int
-subagentx_strcat(char **dst, const char *src)
-{
- char *tmp;
- size_t dstlen = 0, buflen = 0, srclen, nbuflen;
-
- if (*dst != NULL) {
- dstlen = strlen(*dst);
- buflen = ((dstlen / 512) + 1) * 512;
- }
-
- srclen = strlen(src);
- if (*dst == NULL || dstlen + srclen > buflen) {
- nbuflen = (((dstlen + srclen) / 512) + 1) * 512;
- tmp = recallocarray(*dst, buflen, nbuflen, sizeof(*tmp));
- if (tmp == NULL)
- return -1;
- *dst = tmp;
- buflen = nbuflen;
- }
-
- (void)strlcat(*dst, src, buflen);
- return 0;
-}
-
-void
-subagentx_read(struct subagentx *sa)
-{
- struct subagentx_session *sas;
- struct subagentx_context *sac;
- struct subagentx_request sar_search, *sar;
- struct agentx_pdu *pdu;
- int error;
-
- if ((pdu = agentx_recv(sa->sa_ax)) == NULL) {
- if (errno == EAGAIN)
- return;
- subagentx_log_sa_warn(sa, "lost connection");
- subagentx_reset(sa);
- return;
- }
-
- TAILQ_FOREACH(sas, &(sa->sa_sessions), sas_sa_sessions) {
- if (sas->sas_id == pdu->ap_header.aph_sessionid)
- break;
- if (sas->sas_cstate == SA_CSTATE_WAITOPEN &&
- sas->sas_packetid == pdu->ap_header.aph_packetid)
- break;
- }
- if (sas == NULL) {
- subagentx_log_sa_warnx(sa, "received unexpected session: %d",
- pdu->ap_header.aph_sessionid);
- agentx_pdu_free(pdu);
- subagentx_reset(sa);
- return;
- }
- TAILQ_FOREACH(sac, &(sas->sas_contexts), sac_sas_contexts) {
- if ((pdu->ap_header.aph_flags &
- AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT) == 0 &&
- sac->sac_name_default == 1)
- break;
- if (pdu->ap_header.aph_flags &
- AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT &&
- sac->sac_name_default == 0 &&
- pdu->ap_context.aos_slen == sac->sac_name.aos_slen &&
- memcmp(pdu->ap_context.aos_string,
- sac->sac_name.aos_string, sac->sac_name.aos_slen) == 0)
- break;
- }
- if (pdu->ap_header.aph_type != AGENTX_PDU_TYPE_RESPONSE) {
- if (sac == NULL) {
- subagentx_log_sa_warnx(sa, "%s: invalid context",
- pdu->ap_context.aos_string);
- agentx_pdu_free(pdu);
- subagentx_reset(sa);
- return;
- }
- }
-
- switch (pdu->ap_header.aph_type) {
- case AGENTX_PDU_TYPE_GET:
- case AGENTX_PDU_TYPE_GETNEXT:
- case AGENTX_PDU_TYPE_GETBULK:
- subagentx_get_start(sac, pdu);
- break;
- /* Add stubs for set functions */
- case AGENTX_PDU_TYPE_TESTSET:
- case AGENTX_PDU_TYPE_COMMITSET:
- case AGENTX_PDU_TYPE_UNDOSET:
- if (pdu->ap_header.aph_type == AGENTX_PDU_TYPE_TESTSET)
- error = AGENTX_PDU_ERROR_NOTWRITABLE;
- else if (pdu->ap_header.aph_type == AGENTX_PDU_TYPE_COMMITSET)
- error = AGENTX_PDU_ERROR_COMMITFAILED;
- else
- error = AGENTX_PDU_ERROR_UNDOFAILED;
-
- subagentx_log_sac_debug(sac, "unsupported call: %s",
- agentx_pdutype2string(pdu->ap_header.aph_type));
- if (agentx_response(sa->sa_ax, sas->sas_id,
- pdu->ap_header.aph_transactionid,
- pdu->ap_header.aph_packetid,
- sac == NULL ? NULL : SUBAGENTX_CONTEXT_CTX(sac),
- 0, error, 1, NULL, 0) == -1)
- subagentx_log_sac_warn(sac,
- "transaction: %u packetid: %u: failed to send "
- "reply", pdu->ap_header.aph_transactionid,
- pdu->ap_header.aph_packetid);
- if (sa->sa_ax->ax_wblen > 0)
- subagentx_wantwrite(sa, sa->sa_fd);
- break;
- case AGENTX_PDU_TYPE_CLEANUPSET:
- subagentx_log_sa_debug(sa, "unsupported call: %s",
- agentx_pdutype2string(pdu->ap_header.aph_type));
- break;
- case AGENTX_PDU_TYPE_RESPONSE:
- sar_search.sar_packetid = pdu->ap_header.aph_packetid;
- sar = RB_FIND(sa_requests, &(sa->sa_requests), &sar_search);
- if (sar == NULL) {
- if (sac == NULL)
- subagentx_log_sa_warnx(sa, "received "
- "response on non-request");
- else
- subagentx_log_sac_warnx(sac, "received "
- "response on non-request");
- break;
- }
- if (sac != NULL && pdu->ap_payload.ap_response.ap_error == 0) {
- sac->sac_sysuptime =
- pdu->ap_payload.ap_response.ap_uptime;
- (void) clock_gettime(CLOCK_MONOTONIC,
- &(sac->sac_sysuptimespec));
- }
- RB_REMOVE(sa_requests, &(sa->sa_requests), sar);
- (void) sar->sar_cb(pdu, sar->sar_cookie);
- free(sar);
- break;
- default:
- if (sac == NULL)
- subagentx_log_sa_warnx(sa, "unsupported call: %s",
- agentx_pdutype2string(pdu->ap_header.aph_type));
- else
- subagentx_log_sac_warnx(sac, "unsupported call: %s",
- agentx_pdutype2string(pdu->ap_header.aph_type));
- subagentx_reset(sa);
- break;
- }
- agentx_pdu_free(pdu);
-}
-
-void
-subagentx_write(struct subagentx *sa)
-{
- ssize_t send;
-
- if ((send = agentx_send(sa->sa_ax)) == -1) {
- if (errno == EAGAIN) {
- subagentx_wantwrite(sa, sa->sa_fd);
- return;
- }
- subagentx_log_sa_warn(sa, "lost connection");
- subagentx_reset(sa);
- return;
- }
- if (send > 0)
- subagentx_wantwrite(sa, sa->sa_fd);
-}
-
-RB_GENERATE_STATIC(sa_requests, subagentx_request, sar_sa_requests,
- subagentx_request_cmp)
-RB_GENERATE_STATIC(sac_objects, subagentx_object, sao_sac_objects,
- subagentx_object_cmp)
diff --git a/lib/libagentx/subagentx.h b/lib/libagentx/subagentx.h
deleted file mode 100644
index 418b86a78c1..00000000000
--- a/lib/libagentx/subagentx.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <netinet/in.h>
-
-#include <stdint.h>
-#include <stddef.h>
-
-struct subagentx;
-struct subagentx_session;
-struct subagentx_context;
-struct subagentx_agentcaps;
-struct subagentx_region;
-struct subagentx_index;
-struct subagentx_object;
-struct subagentx_varbind;
-
-enum subagentx_request_type {
- SUBAGENTX_REQUEST_TYPE_GET,
- SUBAGENTX_REQUEST_TYPE_GETNEXT,
- SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
-};
-
-#define SUBAGENTX_AGENTX_MASTER "/var/agentx/master"
-#define SUBAGENTX_OID_MAX_LEN 128
-#define SUBAGENTX_OID_INDEX_MAX_LEN 10
-#define SUBAGENTX_MIB2 1, 3, 6, 1, 2, 1
-#define SUBAGENTX_ENTERPRISES 1, 3, 6, 1, 4, 1
-#define SUBAGENTX_OID(...) (uint32_t []) { __VA_ARGS__ }, \
- (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t))
-
-extern void (*subagentx_log_fatal)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-extern void (*subagentx_log_warn)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-extern void (*subagentx_log_info)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-extern void (*subagentx_log_debug)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-
-struct subagentx *subagentx(void (*)(struct subagentx *, void *, int), void *);
-void subagentx_connect(struct subagentx *, int);
-void subagentx_read(struct subagentx *);
-void subagentx_write(struct subagentx *);
-extern void (*subagentx_wantwrite)(struct subagentx *, int);
-void subagentx_free(struct subagentx *);
-struct subagentx_session *subagentx_session(struct subagentx *,
- uint32_t[], size_t, const char *, uint8_t);
-void subagentx_session_free(struct subagentx_session *);
-struct subagentx_context *subagentx_context(struct subagentx_session *,
- const char *);
-struct subagentx_object *subagentx_context_object_find(
- struct subagentx_context *, const uint32_t[], size_t, int, int);
-struct subagentx_object *subagentx_context_object_nfind(
- struct subagentx_context *, const uint32_t[], size_t, int, int);
-uint32_t subagentx_context_uptime(struct subagentx_context *);
-void subagentx_context_free(struct subagentx_context *);
-struct subagentx_agentcaps *subagentx_agentcaps(struct subagentx_context *,
- uint32_t[], size_t, const char *);
-void subagentx_agentcaps_free(struct subagentx_agentcaps *);
-struct subagentx_region *subagentx_region(struct subagentx_context *,
- uint32_t[], size_t, uint8_t);
-void subagentx_region_free(struct subagentx_region *);
-struct subagentx_index *subagentx_index_integer_new(struct subagentx_region *,
- uint32_t[], size_t);
-struct subagentx_index *subagentx_index_integer_any(struct subagentx_region *,
- uint32_t[], size_t);
-struct subagentx_index *subagentx_index_integer_value(struct subagentx_region *,
- uint32_t[], size_t, uint32_t);
-struct subagentx_index *subagentx_index_integer_dynamic(
- struct subagentx_region *, uint32_t[], size_t);
-struct subagentx_index *subagentx_index_string_dynamic(
- struct subagentx_region *, uint32_t[], size_t);
-struct subagentx_index *subagentx_index_nstring_dynamic(
- struct subagentx_region *, uint32_t[], size_t, size_t);
-struct subagentx_index *subagentx_index_oid_dynamic(struct subagentx_region *,
- uint32_t[], size_t);
-struct subagentx_index *subagentx_index_noid_dynamic(struct subagentx_region *,
- uint32_t[], size_t, size_t);
-struct subagentx_index *subagentx_index_ipaddress_dynamic(
- struct subagentx_region *, uint32_t[], size_t);
-void subagentx_index_free(struct subagentx_index *);
-struct subagentx_object *subagentx_object(struct subagentx_region *, uint32_t[],
- size_t, struct subagentx_index *[], size_t, int,
- void (*)(struct subagentx_varbind *));
-void subagentx_object_free(struct subagentx_object *);
-
-void subagentx_varbind_integer(struct subagentx_varbind *, uint32_t);
-void subagentx_varbind_string(struct subagentx_varbind *, const char *);
-void subagentx_varbind_nstring(struct subagentx_varbind *,
- const unsigned char *, size_t);
-void subagentx_varbind_printf(struct subagentx_varbind *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_varbind_null(struct subagentx_varbind *);
-void subagentx_varbind_oid(struct subagentx_varbind *, const uint32_t[],
- size_t);
-void subagentx_varbind_object(struct subagentx_varbind *,
- struct subagentx_object *);
-void subagentx_varbind_index(struct subagentx_varbind *,
- struct subagentx_index *);
-void subagentx_varbind_ipaddress(struct subagentx_varbind *,
- const struct in_addr *);
-void subagentx_varbind_counter32(struct subagentx_varbind *, uint32_t);
-void subagentx_varbind_gauge32(struct subagentx_varbind *, uint32_t);
-void subagentx_varbind_timeticks(struct subagentx_varbind *, uint32_t);
-void subagentx_varbind_opaque(struct subagentx_varbind *, const char *, size_t);
-void subagentx_varbind_counter64(struct subagentx_varbind *, uint64_t);
-void subagentx_varbind_notfound(struct subagentx_varbind *);
-void subagentx_varbind_error(struct subagentx_varbind *);
-
-enum subagentx_request_type subagentx_varbind_request(
- struct subagentx_varbind *);
-struct subagentx_object *
- subagentx_varbind_get_object(struct subagentx_varbind *);
-uint32_t subagentx_varbind_get_index_integer(struct subagentx_varbind *,
- struct subagentx_index *);
-const unsigned char *subagentx_varbind_get_index_string(
- struct subagentx_varbind *, struct subagentx_index *, size_t *, int *);
-const uint32_t *subagentx_varbind_get_index_oid(struct subagentx_varbind *,
- struct subagentx_index *, size_t *, int *);
-const struct in_addr *subagentx_varbind_get_index_ipaddress(
- struct subagentx_varbind *, struct subagentx_index *);
-void subagentx_varbind_set_index_integer(struct subagentx_varbind *,
- struct subagentx_index *, uint32_t);
-void subagentx_varbind_set_index_string(struct subagentx_varbind *,
- struct subagentx_index *, const char *);
-void subagentx_varbind_set_index_nstring(struct subagentx_varbind *,
- struct subagentx_index *, const unsigned char *, size_t);
-void subagentx_varbind_set_index_oid(struct subagentx_varbind *,
- struct subagentx_index *, const uint32_t *, size_t);
-void subagentx_varbind_set_index_object(struct subagentx_varbind *,
- struct subagentx_index *, struct subagentx_object *);
-void subagentx_varbind_set_index_ipaddress(struct subagentx_varbind *,
- struct subagentx_index *, const struct in_addr *);
diff --git a/lib/libagentx/subagentx_internal.h b/lib/libagentx/subagentx_internal.h
deleted file mode 100644
index 4dafcf373a4..00000000000
--- a/lib/libagentx/subagentx_internal.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <sys/queue.h>
-#include <sys/time.h>
-#include <sys/tree.h>
-
-#include "agentx.h"
-
-enum subagentx_cstate { /* Current state */
- SA_CSTATE_CLOSE, /* Closed */
- SA_CSTATE_WAITOPEN, /* Connection requested */
- SA_CSTATE_OPEN, /* Open */
- SA_CSTATE_WAITCLOSE /* Close requested */
-};
-
-enum subagentx_dstate { /* Desired state */
- SA_DSTATE_OPEN, /* Open */
- SA_DSTATE_CLOSE /* Close/free */
-};
-
-struct subagentx {
- void (*sa_nofd)(struct subagentx *, void *, int);
- void *sa_cookie;
- int sa_fd;
- enum subagentx_cstate sa_cstate;
- enum subagentx_dstate sa_dstate;
- struct agentx *sa_ax;
- TAILQ_HEAD(, subagentx_session) sa_sessions;
- TAILQ_HEAD(, subagentx_get) sa_getreqs;
- RB_HEAD(sa_requests, subagentx_request) sa_requests;
-};
-
-struct subagentx_session {
- struct subagentx *sas_sa;
- uint32_t sas_id;
- uint32_t sas_timeout;
- struct agentx_oid sas_oid;
- struct agentx_ostring sas_descr;
- enum subagentx_cstate sas_cstate;
- enum subagentx_dstate sas_dstate;
- uint32_t sas_packetid;
- TAILQ_HEAD(, subagentx_context) sas_contexts;
- TAILQ_ENTRY(subagentx_session) sas_sa_sessions;
-};
-
-struct subagentx_context {
- struct subagentx_session *sac_sas;
- int sac_name_default;
- struct agentx_ostring sac_name;
- uint32_t sac_sysuptime;
- struct timespec sac_sysuptimespec;
- enum subagentx_cstate sac_cstate;
- enum subagentx_dstate sac_dstate;
- TAILQ_HEAD(, subagentx_agentcaps) sac_agentcaps;
- TAILQ_HEAD(, subagentx_region) sac_regions;
- RB_HEAD(sac_objects, subagentx_object) sac_objects;
- TAILQ_ENTRY(subagentx_context) sac_sas_contexts;
-};
-
-struct subagentx_get {
- struct subagentx_context *sag_sac;
- int sag_fd; /* Only used for logging */
- uint32_t sag_sessionid;
- uint32_t sag_transactionid;
- uint32_t sag_packetid;
- int sag_context_default;
- struct agentx_ostring sag_context;
- enum agentx_pdu_type sag_type;
- uint16_t sag_nonrep;
- uint16_t sag_maxrep;
- size_t sag_nvarbind;
- struct subagentx_varbind *sag_varbind;
- TAILQ_ENTRY(subagentx_get) sag_sa_getreqs;
-};
-
-__dead void subagentx_log_sa_fatalx(struct subagentx *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sa_warn(struct subagentx *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sa_warnx(struct subagentx *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sa_info(struct subagentx *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sa_debug(struct subagentx *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-__dead void subagentx_log_sas_fatalx(struct subagentx_session *, const char *,
- ...) __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sas_warnx(struct subagentx_session *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sas_warn(struct subagentx_session *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sas_info(struct subagentx_session *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-__dead void subagentx_log_sac_fatalx(struct subagentx_context *, const char *,
- ...) __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sac_warnx(struct subagentx_context *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sac_warn(struct subagentx_context *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sac_info(struct subagentx_context *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sac_debug(struct subagentx_context *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-__dead void subagentx_log_sag_fatalx(struct subagentx_get *, const char *,
- ...) __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sag_warnx(struct subagentx_get *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sag_warn(struct subagentx_get *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void subagentx_log_sag_debug(struct subagentx_get *, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
diff --git a/lib/libagentx/subagentx_log.c b/lib/libagentx/subagentx_log.c
deleted file mode 100644
index d9dcca8e856..00000000000
--- a/lib/libagentx/subagentx_log.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "subagentx_internal.h"
-
-#define SUBAGENTX_CONTEXT_NAME(sac) (sac->sac_name_default ? "<default>" : \
- (char *)sac->sac_name.aos_string)
-#define SUBAGENTX_GET_CTXNAME(sag) (sag->sag_context_default ? "<default>" : \
- (char *)sag->sag_context.aos_string)
-
-enum subagentx_log_type {
- SUBAGENTX_LOG_TYPE_FATAL,
- SUBAGENTX_LOG_TYPE_WARN,
- SUBAGENTX_LOG_TYPE_INFO,
- SUBAGENTX_LOG_TYPE_DEBUG
-};
-
-void (*subagentx_log_fatal)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2))) = NULL;
-void (*subagentx_log_warn)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2))) = NULL;
-void (*subagentx_log_info)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2))) = NULL;
-void (*subagentx_log_debug)(const char *, ...)
- __attribute__((__format__ (printf, 1, 2))) = NULL;
-
-
-static void
-subagentx_log_do(enum subagentx_log_type, const char *, va_list, int,
- struct subagentx *, struct subagentx_session *, struct subagentx_context *,
- struct subagentx_get *);
-
-void
-subagentx_log_sa_fatalx(struct subagentx *sa, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_FATAL, fmt, ap, 0, sa, NULL, NULL,
- NULL);
- va_end(ap);
- abort();
-}
-
-void
-subagentx_log_sa_warn(struct subagentx *sa, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 1, sa, NULL, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sa_warnx(struct subagentx *sa, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 0, sa, NULL, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sa_info(struct subagentx *sa, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_INFO, fmt, ap, 0, sa, NULL, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sa_debug(struct subagentx *sa, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_DEBUG, fmt, ap, 0, sa, NULL, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sas_fatalx(struct subagentx_session *sas, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_FATAL, fmt, ap, 0, NULL, sas, NULL,
- NULL);
- va_end(ap);
- abort();
-}
-
-void
-subagentx_log_sas_warnx(struct subagentx_session *sas, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 0, NULL, sas, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sas_warn(struct subagentx_session *sas, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 1, NULL, sas, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sas_info(struct subagentx_session *sas, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_INFO, fmt, ap, 0, NULL, sas, NULL,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sac_fatalx(struct subagentx_context *sac, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_FATAL, fmt, ap, 0, NULL, NULL, sac,
- NULL);
- va_end(ap);
- abort();
-}
-
-void
-subagentx_log_sac_warnx(struct subagentx_context *sac, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 0, NULL, NULL, sac,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sac_warn(struct subagentx_context *sac, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 1, NULL, NULL, sac,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sac_info(struct subagentx_context *sac, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_INFO, fmt, ap, 0, NULL, NULL, sac,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sac_debug(struct subagentx_context *sac, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_DEBUG, fmt, ap, 0, NULL, NULL, sac,
- NULL);
- va_end(ap);
-}
-
-void
-subagentx_log_sag_fatalx(struct subagentx_get *sag, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_FATAL, fmt, ap, 0, NULL, NULL, NULL,
- sag);
- va_end(ap);
- abort();
-}
-
-void
-subagentx_log_sag_warnx(struct subagentx_get *sag, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 0, NULL, NULL, NULL,
- sag);
- va_end(ap);
-}
-
-void
-subagentx_log_sag_warn(struct subagentx_get *sag, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_WARN, fmt, ap, 1, NULL, NULL, NULL,
- sag);
- va_end(ap);
-}
-
-void
-subagentx_log_sag_debug(struct subagentx_get *sag, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- subagentx_log_do(SUBAGENTX_LOG_TYPE_DEBUG, fmt, ap, 0, NULL, NULL, NULL,
- sag);
- va_end(ap);
-}
-
-static void
-subagentx_log_do(enum subagentx_log_type type, const char *fmt, va_list ap,
- int useerrno, struct subagentx *sa, struct subagentx_session *sas,
- struct subagentx_context *sac, struct subagentx_get *sag)
-{
- void (*subagentx_log)(const char *, ...);
- char buf[1500];
-
- if (type == SUBAGENTX_LOG_TYPE_FATAL)
- subagentx_log = subagentx_log_fatal;
- else if (type == SUBAGENTX_LOG_TYPE_WARN)
- subagentx_log = subagentx_log_warn;
- else if (type == SUBAGENTX_LOG_TYPE_INFO)
- subagentx_log = subagentx_log_info;
- else
- subagentx_log = subagentx_log_debug;
- if (subagentx_log == NULL)
- return;
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
-
- if (sag != NULL) {
- if (useerrno)
- subagentx_log("[fd:%d sess:%u ctx:%s trid:%u pid:%u]: "
- "%s: %s", sag->sag_fd, sag->sag_sessionid,
- SUBAGENTX_GET_CTXNAME(sag), sag->sag_transactionid,
- sag->sag_packetid, buf, strerror(errno));
- else
- subagentx_log("[fd:%d sess:%u ctx:%s trid:%u pid:%u]: "
- "%s", sag->sag_fd, sag->sag_sessionid,
- SUBAGENTX_GET_CTXNAME(sag), sag->sag_transactionid,
- sag->sag_packetid, buf);
- } else if (sac != NULL) {
- sas = sac->sac_sas;
- sa = sas->sas_sa;
- if (useerrno)
- subagentx_log("[fd:%d sess:%u ctx:%s]: %s: %s",
- sa->sa_fd, sas->sas_id, SUBAGENTX_CONTEXT_NAME(sac),
- buf, strerror(errno));
- else
- subagentx_log("[fd:%d sess:%u ctx:%s]: %s", sa->sa_fd,
- sas->sas_id, SUBAGENTX_CONTEXT_NAME(sac), buf);
- } else if (sas != NULL) {
- sa = sas->sas_sa;
- if (useerrno)
- subagentx_log("[fd:%d sess:%u]: %s: %s", sa->sa_fd,
- sas->sas_id, buf, strerror(errno));
- else
- subagentx_log("[fd:%d sess:%u]: %s", sa->sa_fd,
- sas->sas_id, buf);
- } else if (sa->sa_fd == -1) {
- if (useerrno)
- subagentx_log("%s: %s", buf, strerror(errno));
- else
- subagentx_log("%s", buf);
- } else {
- if (useerrno)
- subagentx_log("[fd:%d]: %s: %s", sa->sa_fd, buf,
- strerror(errno));
- else
- subagentx_log("[fd:%d]: %s", sa->sa_fd, buf);
- }
-}