xref: /openbsd-src/lib/libagentx/agentx.c (revision c5fcbd5a825aa453de919826c57d87e64d2c4d72)
1*c5fcbd5aSmartijn /*	$OpenBSD: agentx.c,v 1.24 2023/10/29 11:10:07 martijn Exp $ */
29dbe2cd1Smartijn /*
39dbe2cd1Smartijn  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
49dbe2cd1Smartijn  *
59dbe2cd1Smartijn  * Permission to use, copy, modify, and distribute this software for any
69dbe2cd1Smartijn  * purpose with or without fee is hereby granted, provided that the above
79dbe2cd1Smartijn  * copyright notice and this permission notice appear in all copies.
89dbe2cd1Smartijn  *
99dbe2cd1Smartijn  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109dbe2cd1Smartijn  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119dbe2cd1Smartijn  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129dbe2cd1Smartijn  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139dbe2cd1Smartijn  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149dbe2cd1Smartijn  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159dbe2cd1Smartijn  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169dbe2cd1Smartijn  */
1781180db9Smartijn #include <netinet/in.h>
189dbe2cd1Smartijn 
199dbe2cd1Smartijn #include <errno.h>
2081180db9Smartijn #include <stdarg.h>
219dbe2cd1Smartijn #include <stdlib.h>
229dbe2cd1Smartijn #include <stdio.h>
239dbe2cd1Smartijn #include <string.h>
249dbe2cd1Smartijn #include <strings.h>
2581180db9Smartijn #include <time.h>
269dbe2cd1Smartijn #include <unistd.h>
279dbe2cd1Smartijn 
2881180db9Smartijn #include "agentx_internal.h"
29fb16b9d1Sderaadt #include <agentx.h>
309dbe2cd1Smartijn 
317d7f9aadSmartijn /*
327d7f9aadSmartijn  * ax:		struct agentx
337d7f9aadSmartijn  * axs:		struct agentx_session
347d7f9aadSmartijn  * axc:		struct agentx_context
357d7f9aadSmartijn  * axr:		struct agentx_region
367d7f9aadSmartijn  * axi:		struct agentx_index
377d7f9aadSmartijn  * axo:		struct agentx_object
387d7f9aadSmartijn  * axg:		struct agentx_get
397d7f9aadSmartijn  * axv:		struct agentx_varbind
407d7f9aadSmartijn  * axr:		struct agentx_request
417d7f9aadSmartijn  * cstate:	current state
427d7f9aadSmartijn  * dstate:	desired state
437d7f9aadSmartijn  */
447d7f9aadSmartijn 
4581180db9Smartijn enum agentx_index_type {
4681180db9Smartijn 	AXI_TYPE_NEW,
4781180db9Smartijn 	AXI_TYPE_ANY,
4881180db9Smartijn 	AXI_TYPE_VALUE,
4981180db9Smartijn 	AXI_TYPE_DYNAMIC
5081180db9Smartijn };
519dbe2cd1Smartijn 
5281180db9Smartijn #define AGENTX_CONTEXT_CTX(axc) (axc->axc_name_default ? NULL : \
5381180db9Smartijn     &(axc->axc_name))
5481180db9Smartijn 
5581180db9Smartijn struct agentx_agentcaps {
5681180db9Smartijn 	struct agentx_context *axa_axc;
5781180db9Smartijn 	struct ax_oid axa_oid;
5881180db9Smartijn 	struct ax_ostring axa_descr;
5981180db9Smartijn 	enum agentx_cstate axa_cstate;
6081180db9Smartijn 	enum agentx_dstate axa_dstate;
6181180db9Smartijn 	TAILQ_ENTRY(agentx_agentcaps) axa_axc_agentcaps;
6281180db9Smartijn };
6381180db9Smartijn 
6481180db9Smartijn struct agentx_region {
6581180db9Smartijn 	struct agentx_context *axr_axc;
6681180db9Smartijn 	struct ax_oid axr_oid;
6781180db9Smartijn 	uint8_t axr_timeout;
6881180db9Smartijn 	uint8_t axr_priority;
6981180db9Smartijn 	enum agentx_cstate axr_cstate;
7081180db9Smartijn 	enum agentx_dstate axr_dstate;
7181180db9Smartijn 	TAILQ_HEAD(, agentx_index) axr_indices;
7281180db9Smartijn 	TAILQ_HEAD(, agentx_object) axr_objects;
7381180db9Smartijn 	TAILQ_ENTRY(agentx_region) axr_axc_regions;
7481180db9Smartijn };
7581180db9Smartijn 
7681180db9Smartijn struct agentx_index {
7781180db9Smartijn 	struct agentx_region *axi_axr;
7881180db9Smartijn 	enum agentx_index_type axi_type;
7981180db9Smartijn 	struct ax_varbind axi_vb;
8081180db9Smartijn 	struct agentx_object **axi_object;
8181180db9Smartijn 	size_t axi_objectlen;
8281180db9Smartijn 	size_t axi_objectsize;
8381180db9Smartijn 	enum agentx_cstate axi_cstate;
8481180db9Smartijn 	enum agentx_dstate axi_dstate;
8581180db9Smartijn 	TAILQ_ENTRY(agentx_index) axi_axr_indices;
8681180db9Smartijn };
8781180db9Smartijn 
8881180db9Smartijn struct agentx_object {
8981180db9Smartijn 	struct agentx_region *axo_axr;
9081180db9Smartijn 	struct ax_oid axo_oid;
9181180db9Smartijn 	struct agentx_index *axo_index[AGENTX_OID_INDEX_MAX_LEN];
9281180db9Smartijn 	size_t axo_indexlen;
9381180db9Smartijn 	int axo_implied;
9481180db9Smartijn 	uint8_t axo_timeout;
9581180db9Smartijn 	/* Prevent freeing object while in use by get and set requesets */
9681180db9Smartijn 	uint32_t axo_lock;
9781180db9Smartijn 	void (*axo_get)(struct agentx_varbind *);
9881180db9Smartijn 	enum agentx_cstate axo_cstate;
9981180db9Smartijn 	enum agentx_dstate axo_dstate;
10081180db9Smartijn 	RB_ENTRY(agentx_object) axo_axc_objects;
10181180db9Smartijn 	TAILQ_ENTRY(agentx_object) axo_axr_objects;
10281180db9Smartijn };
10381180db9Smartijn 
10481180db9Smartijn struct agentx_varbind {
10581180db9Smartijn 	struct agentx_get *axv_axg;
10681180db9Smartijn 	struct agentx_object *axv_axo;
10781180db9Smartijn 	struct agentx_varbind_index {
10881180db9Smartijn 		struct agentx_index *axv_axi;
10981180db9Smartijn 		union ax_data axv_idata;
11081180db9Smartijn 	} axv_index[AGENTX_OID_INDEX_MAX_LEN];
11181180db9Smartijn 	size_t axv_indexlen;
11281180db9Smartijn 	int axv_initialized;
11381180db9Smartijn 	int axv_include;
11481180db9Smartijn 	struct ax_varbind axv_vb;
11581180db9Smartijn 	struct ax_oid axv_start;
11681180db9Smartijn 	struct ax_oid axv_end;
11781180db9Smartijn 	enum ax_pdu_error axv_error;
11881180db9Smartijn };
11981180db9Smartijn 
12081180db9Smartijn #define AGENTX_GET_CTX(axg) (axg->axg_context_default ? NULL : \
12181180db9Smartijn     &(axg->axg_context))
12281180db9Smartijn struct agentx_request {
12381180db9Smartijn 	uint32_t axr_packetid;
12481180db9Smartijn 	int (*axr_cb)(struct ax_pdu *, void *);
12581180db9Smartijn 	void *axr_cookie;
12681180db9Smartijn 	RB_ENTRY(agentx_request) axr_ax_requests;
12781180db9Smartijn };
12881180db9Smartijn 
12981180db9Smartijn static void agentx_start(struct agentx *);
13081180db9Smartijn static void agentx_finalize(struct agentx *, int);
13181180db9Smartijn static void agentx_wantwritenow(struct agentx *, int);
13281180db9Smartijn void (*agentx_wantwrite)(struct agentx *, int) =
13381180db9Smartijn     agentx_wantwritenow;
13481180db9Smartijn static void agentx_reset(struct agentx *);
13581180db9Smartijn static void agentx_free_finalize(struct agentx *);
13667d8ab44Smartijn static int agentx_session_retry(struct agentx_session *);
13781180db9Smartijn static int agentx_session_start(struct agentx_session *);
13881180db9Smartijn static int agentx_session_finalize(struct ax_pdu *, void *);
13981180db9Smartijn static int agentx_session_close(struct agentx_session *,
14081180db9Smartijn     enum ax_close_reason);
14181180db9Smartijn static int agentx_session_close_finalize(struct ax_pdu *, void *);
14281180db9Smartijn static void agentx_session_free_finalize(struct agentx_session *);
14381180db9Smartijn static void agentx_session_reset(struct agentx_session *);
14467d8ab44Smartijn static int agentx_context_retry(struct agentx_context *);
14581180db9Smartijn static void agentx_context_start(struct agentx_context *);
14681180db9Smartijn static void agentx_context_free_finalize(struct agentx_context *);
14781180db9Smartijn static void agentx_context_reset(struct agentx_context *);
14881180db9Smartijn static int agentx_agentcaps_start(struct agentx_agentcaps *);
14981180db9Smartijn static int agentx_agentcaps_finalize(struct ax_pdu *, void *);
15081180db9Smartijn static int agentx_agentcaps_close(struct agentx_agentcaps *);
15181180db9Smartijn static int agentx_agentcaps_close_finalize(struct ax_pdu *, void *);
15281180db9Smartijn static void agentx_agentcaps_free_finalize(struct agentx_agentcaps *);
15381180db9Smartijn static void agentx_agentcaps_reset(struct agentx_agentcaps *);
15467d8ab44Smartijn static int agentx_region_retry(struct agentx_region *);
15581180db9Smartijn static int agentx_region_start(struct agentx_region *);
15681180db9Smartijn static int agentx_region_finalize(struct ax_pdu *, void *);
15781180db9Smartijn static int agentx_region_close(struct agentx_region *);
15881180db9Smartijn static int agentx_region_close_finalize(struct ax_pdu *, void *);
15981180db9Smartijn static void agentx_region_free_finalize(struct agentx_region *);
16081180db9Smartijn static void agentx_region_reset(struct agentx_region *);
16181180db9Smartijn static struct agentx_index *agentx_index(struct agentx_region *,
16281180db9Smartijn     struct ax_varbind *, enum agentx_index_type);
16381180db9Smartijn static int agentx_index_start(struct agentx_index *);
16481180db9Smartijn static int agentx_index_finalize(struct ax_pdu *, void *);
16581180db9Smartijn static void agentx_index_free_finalize(struct agentx_index *);
16681180db9Smartijn static void agentx_index_reset(struct agentx_index *);
16781180db9Smartijn static int agentx_index_close(struct agentx_index *);
16881180db9Smartijn static int agentx_index_close_finalize(struct ax_pdu *, void *);
16981180db9Smartijn static int agentx_object_start(struct agentx_object *);
17081180db9Smartijn static int agentx_object_finalize(struct ax_pdu *, void *);
17181180db9Smartijn static int agentx_object_lock(struct agentx_object *);
17281180db9Smartijn static void agentx_object_unlock(struct agentx_object *);
17381180db9Smartijn static int agentx_object_close(struct agentx_object *);
17481180db9Smartijn static int agentx_object_close_finalize(struct ax_pdu *, void *);
17581180db9Smartijn static void agentx_object_free_finalize(struct agentx_object *);
17681180db9Smartijn static void agentx_object_reset(struct agentx_object *);
17781180db9Smartijn static int agentx_object_cmp(struct agentx_object *,
17881180db9Smartijn     struct agentx_object *);
17981180db9Smartijn static void agentx_get_start(struct agentx_context *,
18081180db9Smartijn     struct ax_pdu *);
18181180db9Smartijn static void agentx_get_finalize(struct agentx_get *);
18281180db9Smartijn static void agentx_get_free(struct agentx_get *);
18381180db9Smartijn static void agentx_varbind_start(struct agentx_varbind *);
18481180db9Smartijn static void agentx_varbind_finalize(struct agentx_varbind *);
18581180db9Smartijn static void agentx_varbind_nosuchobject(struct agentx_varbind *);
18681180db9Smartijn static void agentx_varbind_nosuchinstance(struct agentx_varbind *);
18781180db9Smartijn static void agentx_varbind_endofmibview(struct agentx_varbind *);
18881180db9Smartijn static void agentx_varbind_error_type(struct agentx_varbind *,
18981180db9Smartijn     enum ax_pdu_error, int);
19081180db9Smartijn static int agentx_request(struct agentx *, uint32_t,
19181180db9Smartijn     int (*)(struct ax_pdu *, void *), void *);
19281180db9Smartijn static int agentx_request_cmp(struct agentx_request *,
19381180db9Smartijn     struct agentx_request *);
19481180db9Smartijn static int agentx_strcat(char **, const char *);
1959c70cf54Smartijn static int agentx_oidfill(struct ax_oid *, const uint32_t[], size_t,
1969c70cf54Smartijn     const char **);
19781180db9Smartijn 
RB_PROTOTYPE_STATIC(ax_requests,agentx_request,axr_ax_requests,agentx_request_cmp)19881180db9Smartijn RB_PROTOTYPE_STATIC(ax_requests, agentx_request, axr_ax_requests,
19981180db9Smartijn     agentx_request_cmp)
20081180db9Smartijn RB_PROTOTYPE_STATIC(axc_objects, agentx_object, axo_axc_objects,
20181180db9Smartijn     agentx_object_cmp)
2029dbe2cd1Smartijn 
2039dbe2cd1Smartijn struct agentx *
20481180db9Smartijn agentx(void (*nofd)(struct agentx *, void *, int), void *cookie)
2059dbe2cd1Smartijn {
2069dbe2cd1Smartijn 	struct agentx *ax;
2079dbe2cd1Smartijn 
2089dbe2cd1Smartijn 	if ((ax = calloc(1, sizeof(*ax))) == NULL)
2099dbe2cd1Smartijn 		return NULL;
21081180db9Smartijn 
21181180db9Smartijn 	ax->ax_nofd = nofd;
21281180db9Smartijn 	ax->ax_cookie = cookie;
21381180db9Smartijn 	ax->ax_fd = -1;
21481180db9Smartijn 	ax->ax_cstate = AX_CSTATE_CLOSE;
21581180db9Smartijn 	ax->ax_dstate = AX_DSTATE_OPEN;
21681180db9Smartijn 	TAILQ_INIT(&(ax->ax_sessions));
21781180db9Smartijn 	TAILQ_INIT(&(ax->ax_getreqs));
21881180db9Smartijn 	RB_INIT(&(ax->ax_requests));
21981180db9Smartijn 
22081180db9Smartijn 	agentx_start(ax);
2219dbe2cd1Smartijn 
2229dbe2cd1Smartijn 	return ax;
22381180db9Smartijn }
2249dbe2cd1Smartijn 
22581180db9Smartijn /*
22681180db9Smartijn  * agentx_finalize is not a suitable name for a public API,
22781180db9Smartijn  * but use it internally for consistency
22881180db9Smartijn  */
22981180db9Smartijn void
agentx_connect(struct agentx * ax,int fd)23081180db9Smartijn agentx_connect(struct agentx *ax, int fd)
23181180db9Smartijn {
23281180db9Smartijn 	agentx_finalize(ax, fd);
23381180db9Smartijn }
23481180db9Smartijn 
23567d8ab44Smartijn void
agentx_retry(struct agentx * ax)23667d8ab44Smartijn agentx_retry(struct agentx *ax)
23767d8ab44Smartijn {
23867d8ab44Smartijn 	struct agentx_session *axs;
23967d8ab44Smartijn 
24067d8ab44Smartijn 	if (ax->ax_fd == -1)
24167d8ab44Smartijn 		return;
24267d8ab44Smartijn 
24367d8ab44Smartijn 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
24467d8ab44Smartijn 		if (axs->axs_cstate == AX_CSTATE_OPEN) {
24567d8ab44Smartijn 			if (agentx_session_retry(axs) == -1)
24667d8ab44Smartijn 				return;
24767d8ab44Smartijn 		} else if (axs->axs_cstate == AX_CSTATE_CLOSE) {
24867d8ab44Smartijn 			if (agentx_session_start(axs) == -1)
24967d8ab44Smartijn 				return;
25067d8ab44Smartijn 		}
25167d8ab44Smartijn 	}
25267d8ab44Smartijn }
25367d8ab44Smartijn 
25481180db9Smartijn static void
agentx_start(struct agentx * ax)25581180db9Smartijn agentx_start(struct agentx *ax)
25681180db9Smartijn {
25781180db9Smartijn #ifdef AX_DEBUG
25881180db9Smartijn 	if (ax->ax_cstate != AX_CSTATE_CLOSE ||
25981180db9Smartijn 	    ax->ax_dstate != AX_DSTATE_OPEN)
26081180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: unexpected connect", __func__);
26181180db9Smartijn #endif
26281180db9Smartijn 	ax->ax_cstate = AX_CSTATE_WAITOPEN;
26381180db9Smartijn 	ax->ax_nofd(ax, ax->ax_cookie, 0);
26481180db9Smartijn }
26581180db9Smartijn 
26681180db9Smartijn static void
agentx_finalize(struct agentx * ax,int fd)26781180db9Smartijn agentx_finalize(struct agentx *ax, int fd)
26881180db9Smartijn {
26981180db9Smartijn 	struct agentx_session *axs;
27081180db9Smartijn 
27181180db9Smartijn 	if (ax->ax_cstate != AX_CSTATE_WAITOPEN) {
27281180db9Smartijn #ifdef AX_DEBUG
27381180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: agentx unexpected connect",
27481180db9Smartijn 		    __func__);
27581180db9Smartijn #else
27681180db9Smartijn 		agentx_log_ax_warnx(ax,
27781180db9Smartijn 		    "%s: agentx unexpected connect: ignoring", __func__);
27881180db9Smartijn 		return;
27981180db9Smartijn #endif
28081180db9Smartijn 	}
28181180db9Smartijn 	if ((ax->ax_ax = ax_new(fd)) == NULL) {
28281180db9Smartijn 		agentx_log_ax_warn(ax, "failed to initialize");
28381180db9Smartijn 		close(fd);
28481180db9Smartijn 		agentx_reset(ax);
28581180db9Smartijn 		return;
28681180db9Smartijn 	}
28781180db9Smartijn 
28881180db9Smartijn 	agentx_log_ax_info(ax, "new connection: %d", fd);
28981180db9Smartijn 
29081180db9Smartijn 	ax->ax_fd = fd;
29181180db9Smartijn 	ax->ax_cstate = AX_CSTATE_OPEN;
29281180db9Smartijn 
29381180db9Smartijn 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
29481180db9Smartijn 		if (agentx_session_start(axs) == -1)
29581180db9Smartijn 			break;
29681180db9Smartijn 	}
29781180db9Smartijn }
29881180db9Smartijn 
29981180db9Smartijn static void
agentx_wantwritenow(struct agentx * ax,int fd)30081180db9Smartijn agentx_wantwritenow(struct agentx *ax, int fd)
30181180db9Smartijn {
30281180db9Smartijn 	agentx_write(ax);
30381180db9Smartijn }
30481180db9Smartijn 
30581180db9Smartijn static void
agentx_reset(struct agentx * ax)30681180db9Smartijn agentx_reset(struct agentx *ax)
30781180db9Smartijn {
30833598f3aSmartijn 	struct agentx_session *axs, *taxs;
30981180db9Smartijn 	struct agentx_request *axr;
31081180db9Smartijn 	struct agentx_get *axg;
311f00a771dSmartijn 	int axfree = ax->ax_free;
31281180db9Smartijn 
31381180db9Smartijn 	ax_free(ax->ax_ax);
31481180db9Smartijn 	ax->ax_ax = NULL;
31581180db9Smartijn 	ax->ax_fd = -1;
316f00a771dSmartijn 	ax->ax_free = 1;
31781180db9Smartijn 
31881180db9Smartijn 	ax->ax_cstate = AX_CSTATE_CLOSE;
31981180db9Smartijn 
32081180db9Smartijn 	while ((axr = RB_MIN(ax_requests, &(ax->ax_requests))) != NULL) {
32181180db9Smartijn 		RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
32281180db9Smartijn 		free(axr);
32381180db9Smartijn 	}
32433598f3aSmartijn 	TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
32581180db9Smartijn 		agentx_session_reset(axs);
32681180db9Smartijn 	while (!TAILQ_EMPTY(&(ax->ax_getreqs))) {
32781180db9Smartijn 		axg = TAILQ_FIRST(&(ax->ax_getreqs));
32881180db9Smartijn 		axg->axg_axc = NULL;
32981180db9Smartijn 		TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
33081180db9Smartijn 	}
33181180db9Smartijn 
332f00a771dSmartijn 	if (ax->ax_dstate == AX_DSTATE_OPEN)
33381180db9Smartijn 		agentx_start(ax);
334f00a771dSmartijn 
335f00a771dSmartijn 	if (!axfree)
336f00a771dSmartijn 		agentx_free_finalize(ax);
3379dbe2cd1Smartijn }
3389dbe2cd1Smartijn 
3399dbe2cd1Smartijn void
agentx_free(struct agentx * ax)3409dbe2cd1Smartijn agentx_free(struct agentx *ax)
3419dbe2cd1Smartijn {
34233598f3aSmartijn 	struct agentx_session *axs, *taxs;
343f00a771dSmartijn 	int axfree;
34481180db9Smartijn 
3459dbe2cd1Smartijn 	if (ax == NULL)
3469dbe2cd1Smartijn 		return;
34781180db9Smartijn 
348f00a771dSmartijn 	axfree = ax->ax_free;
349f00a771dSmartijn 	ax->ax_free = 1;
350f00a771dSmartijn 
35181180db9Smartijn 	/* Malloc throws abort on invalid pointers as well */
352f00a771dSmartijn 	if (ax->ax_dstate == AX_DSTATE_CLOSE)
35381180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: double free", __func__);
35481180db9Smartijn 	ax->ax_dstate = AX_DSTATE_CLOSE;
35581180db9Smartijn 
35633598f3aSmartijn 	TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs) {
35781180db9Smartijn 		if (axs->axs_dstate != AX_DSTATE_CLOSE)
35881180db9Smartijn 			agentx_session_free(axs);
35981180db9Smartijn 	}
360f00a771dSmartijn 	if (!axfree)
36181180db9Smartijn 		agentx_free_finalize(ax);
36281180db9Smartijn }
36381180db9Smartijn 
36481180db9Smartijn static void
agentx_free_finalize(struct agentx * ax)36581180db9Smartijn agentx_free_finalize(struct agentx *ax)
36681180db9Smartijn {
367f00a771dSmartijn 	struct agentx_session *axs, *taxs;
368f00a771dSmartijn 
369f00a771dSmartijn 	ax->ax_free = 0;
370f00a771dSmartijn 
371f00a771dSmartijn 	TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
372f00a771dSmartijn 		agentx_session_free_finalize(axs);
373f00a771dSmartijn 
374f00a771dSmartijn 	if (!TAILQ_EMPTY(&(ax->ax_sessions)) ||
375f00a771dSmartijn 	    !RB_EMPTY(&(ax->ax_requests)) ||
376f00a771dSmartijn 	    ax->ax_dstate != AX_DSTATE_CLOSE)
377f00a771dSmartijn 		return;
37881180db9Smartijn 
37981180db9Smartijn 	ax_free(ax->ax_ax);
38081180db9Smartijn 	ax->ax_nofd(ax, ax->ax_cookie, 1);
3819dbe2cd1Smartijn 	free(ax);
3829dbe2cd1Smartijn }
3839dbe2cd1Smartijn 
38481180db9Smartijn struct agentx_session *
agentx_session(struct agentx * ax,uint32_t oid[],size_t oidlen,const char * descr,uint8_t timeout)38581180db9Smartijn agentx_session(struct agentx *ax, uint32_t oid[],
38681180db9Smartijn     size_t oidlen, const char *descr, uint8_t timeout)
3879dbe2cd1Smartijn {
38881180db9Smartijn 	struct agentx_session *axs;
3899c70cf54Smartijn 	const char *errstr;
3909dbe2cd1Smartijn 
39181180db9Smartijn 	if ((axs = calloc(1, sizeof(*axs))) == NULL)
3929dbe2cd1Smartijn 		return NULL;
39381180db9Smartijn 
39481180db9Smartijn 	axs->axs_ax = ax;
39581180db9Smartijn 	axs->axs_timeout = timeout;
3969c70cf54Smartijn 	/* RFC 2741 section 6.2.1: may send a null Object Identifier */
3979c70cf54Smartijn 	if (oidlen == 0)
39881180db9Smartijn 		axs->axs_oid.aoi_idlen = oidlen;
3999c70cf54Smartijn 	else {
4009c70cf54Smartijn 		if (agentx_oidfill((&axs->axs_oid), oid, oidlen,
4019c70cf54Smartijn 		    &errstr) == -1) {
4029c70cf54Smartijn #ifdef AX_DEBUG
4039c70cf54Smartijn 			agentx_log_ax_fatalx(ax, "%s: %s", __func__, errstr);
4049c70cf54Smartijn #else
4059c70cf54Smartijn 			return NULL;
4069c70cf54Smartijn #endif
4079c70cf54Smartijn 		}
4089c70cf54Smartijn 	}
40981180db9Smartijn 	axs->axs_descr.aos_string = (unsigned char *)strdup(descr);
41081180db9Smartijn 	if (axs->axs_descr.aos_string == NULL) {
41181180db9Smartijn 		free(axs);
41281180db9Smartijn 		return NULL;
41381180db9Smartijn 	}
41481180db9Smartijn 	axs->axs_descr.aos_slen = strlen(descr);
41581180db9Smartijn 	axs->axs_cstate = AX_CSTATE_CLOSE;
41681180db9Smartijn 	axs->axs_dstate = AX_DSTATE_OPEN;
41781180db9Smartijn 	TAILQ_INIT(&(axs->axs_contexts));
41881180db9Smartijn 	TAILQ_INSERT_HEAD(&(ax->ax_sessions), axs, axs_ax_sessions);
41981180db9Smartijn 
42081180db9Smartijn 	if (ax->ax_cstate == AX_CSTATE_OPEN)
42181180db9Smartijn 		(void) agentx_session_start(axs);
42281180db9Smartijn 
42381180db9Smartijn 	return axs;
4249dbe2cd1Smartijn }
4259dbe2cd1Smartijn 
4269dbe2cd1Smartijn static int
agentx_session_retry(struct agentx_session * axs)42767d8ab44Smartijn agentx_session_retry(struct agentx_session *axs)
42867d8ab44Smartijn {
42967d8ab44Smartijn 	struct agentx_context *axc;
43067d8ab44Smartijn 
43167d8ab44Smartijn #ifdef AX_DEBUG
43267d8ab44Smartijn 	if (axs->axs_cstate != AX_CSTATE_OPEN)
43367d8ab44Smartijn 		agentx_log_axs_fatalx(axs, "%s: unexpected retry", __func__);
43467d8ab44Smartijn #endif
43567d8ab44Smartijn 
43667d8ab44Smartijn 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts) {
43767d8ab44Smartijn 		if (axc->axc_cstate == AX_CSTATE_OPEN) {
43867d8ab44Smartijn 			if (agentx_context_retry(axc) == -1)
43967d8ab44Smartijn 				return -1;
44067d8ab44Smartijn 		} else if (axc->axc_cstate == AX_CSTATE_CLOSE)
44167d8ab44Smartijn 			agentx_context_start(axc);
44267d8ab44Smartijn 	}
44367d8ab44Smartijn 	return 0;
44467d8ab44Smartijn }
44567d8ab44Smartijn 
44667d8ab44Smartijn static int
agentx_session_start(struct agentx_session * axs)44781180db9Smartijn agentx_session_start(struct agentx_session *axs)
4489dbe2cd1Smartijn {
44981180db9Smartijn 	struct agentx *ax = axs->axs_ax;
45081180db9Smartijn 	uint32_t packetid;
4519dbe2cd1Smartijn 
45281180db9Smartijn #ifdef AX_DEBUG
45381180db9Smartijn 	if (ax->ax_cstate != AX_CSTATE_OPEN ||
45481180db9Smartijn 	    axs->axs_cstate != AX_CSTATE_CLOSE ||
45581180db9Smartijn 	    axs->axs_dstate != AX_DSTATE_OPEN)
45681180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: unexpected session open",
45781180db9Smartijn 		    __func__);
45881180db9Smartijn #endif
45981180db9Smartijn 	packetid = ax_open(ax->ax_ax, axs->axs_timeout, &(axs->axs_oid),
46081180db9Smartijn 	    &(axs->axs_descr));
46181180db9Smartijn 	if (packetid == 0) {
46281180db9Smartijn 		agentx_log_ax_warn(ax, "couldn't generate %s",
46381180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_OPEN));
46481180db9Smartijn 		agentx_reset(ax);
4659dbe2cd1Smartijn 		return -1;
4669dbe2cd1Smartijn 	}
46781180db9Smartijn 	axs->axs_packetid = packetid;
46881180db9Smartijn 	agentx_log_ax_info(ax, "opening session");
46981180db9Smartijn 	axs->axs_cstate = AX_CSTATE_WAITOPEN;
47081180db9Smartijn 	return agentx_request(ax, packetid, agentx_session_finalize, axs);
4719dbe2cd1Smartijn }
4729dbe2cd1Smartijn 
47381180db9Smartijn static int
agentx_session_finalize(struct ax_pdu * pdu,void * cookie)47481180db9Smartijn agentx_session_finalize(struct ax_pdu *pdu, void *cookie)
4759dbe2cd1Smartijn {
47681180db9Smartijn 	struct agentx_session *axs = cookie;
47781180db9Smartijn 	struct agentx *ax = axs->axs_ax;
47881180db9Smartijn 	struct agentx_context *axc;
4799dbe2cd1Smartijn 
48081180db9Smartijn #ifdef AX_DEBUG
48181180db9Smartijn 	if (axs->axs_cstate != AX_CSTATE_WAITOPEN)
48281180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: not expecting new session",
48381180db9Smartijn 		    __func__);
4849dbe2cd1Smartijn #endif
4859dbe2cd1Smartijn 
48681180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
48781180db9Smartijn 		agentx_log_ax_warnx(ax, "failed to open session: %s",
48881180db9Smartijn 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
4898fea2aa4Smartijn 		axs->axs_cstate = AX_CSTATE_CLOSE;
4909dbe2cd1Smartijn 		return -1;
4919dbe2cd1Smartijn 	}
4929dbe2cd1Smartijn 
49381180db9Smartijn 	axs->axs_id = pdu->ap_header.aph_sessionid;
49481180db9Smartijn 	axs->axs_cstate = AX_CSTATE_OPEN;
49581180db9Smartijn 
49681180db9Smartijn 	if (axs->axs_dstate == AX_DSTATE_CLOSE) {
49781180db9Smartijn 		agentx_session_close(axs, AX_CLOSE_SHUTDOWN);
49881180db9Smartijn 		return 0;
49981180db9Smartijn 	}
50081180db9Smartijn 
50181180db9Smartijn 	agentx_log_axs_info(axs, "open");
50281180db9Smartijn 
50381180db9Smartijn 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts)
50481180db9Smartijn 		agentx_context_start(axc);
50581180db9Smartijn 	return 0;
50681180db9Smartijn }
50781180db9Smartijn 
50881180db9Smartijn static int
agentx_session_close(struct agentx_session * axs,enum ax_close_reason reason)50981180db9Smartijn agentx_session_close(struct agentx_session *axs,
51081180db9Smartijn     enum ax_close_reason reason)
5119dbe2cd1Smartijn {
51281180db9Smartijn 	struct agentx *ax = axs->axs_ax;
51381180db9Smartijn 	uint32_t packetid;
5149dbe2cd1Smartijn 
51581180db9Smartijn #ifdef AX_DEBUG
51681180db9Smartijn 	if (axs->axs_cstate != AX_CSTATE_OPEN)
51781180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: unexpected session close",
51881180db9Smartijn 		    __func__);
51981180db9Smartijn #endif
52081180db9Smartijn 	if ((packetid = ax_close(ax->ax_ax, axs->axs_id, reason)) == 0) {
52181180db9Smartijn 		agentx_log_axs_warn(axs, "couldn't generate %s",
52281180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_CLOSE));
52381180db9Smartijn 		agentx_reset(ax);
5249dbe2cd1Smartijn 		return -1;
52581180db9Smartijn 	}
5269dbe2cd1Smartijn 
52781180db9Smartijn 	agentx_log_axs_info(axs, "closing session: %s",
52881180db9Smartijn 	    ax_closereason2string(reason));
5299dbe2cd1Smartijn 
53081180db9Smartijn 	axs->axs_cstate = AX_CSTATE_WAITCLOSE;
53181180db9Smartijn 	return agentx_request(ax, packetid, agentx_session_close_finalize,
53281180db9Smartijn 	    axs);
53381180db9Smartijn }
53481180db9Smartijn 
53581180db9Smartijn static int
agentx_session_close_finalize(struct ax_pdu * pdu,void * cookie)53681180db9Smartijn agentx_session_close_finalize(struct ax_pdu *pdu, void *cookie)
53781180db9Smartijn {
53881180db9Smartijn 	struct agentx_session *axs = cookie;
53981180db9Smartijn 	struct agentx *ax = axs->axs_ax;
54033598f3aSmartijn 	struct agentx_context *axc, *taxc;
541f00a771dSmartijn 	int axfree = ax->ax_free;
54281180db9Smartijn 
54381180db9Smartijn #ifdef AX_DEBUG
54481180db9Smartijn 	if (axs->axs_cstate != AX_CSTATE_WAITCLOSE)
54581180db9Smartijn 		agentx_log_axs_fatalx(axs, "%s: not expecting session close",
54681180db9Smartijn 		    __func__);
54781180db9Smartijn #endif
54881180db9Smartijn 
54981180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
55081180db9Smartijn 		agentx_log_axs_warnx(axs, "failed to close session: %s",
55181180db9Smartijn 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
55281180db9Smartijn 		agentx_reset(ax);
5539dbe2cd1Smartijn 		return -1;
55481180db9Smartijn 	}
55581180db9Smartijn 
55681180db9Smartijn 	axs->axs_cstate = AX_CSTATE_CLOSE;
557f00a771dSmartijn 	ax->ax_free = 1;
55881180db9Smartijn 
55981180db9Smartijn 	agentx_log_axs_info(axs, "closed");
56081180db9Smartijn 
56133598f3aSmartijn 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
56281180db9Smartijn 		agentx_context_reset(axc);
56381180db9Smartijn 
564f00a771dSmartijn 	if (ax->ax_cstate == AX_CSTATE_OPEN &&
565f00a771dSmartijn 	    axs->axs_dstate == AX_DSTATE_OPEN)
566f00a771dSmartijn 		agentx_session_start(axs);
567f00a771dSmartijn 	if (!axfree)
568f00a771dSmartijn 		agentx_free_finalize(ax);
569f00a771dSmartijn 
5709dbe2cd1Smartijn 	return 0;
5719dbe2cd1Smartijn }
5729dbe2cd1Smartijn 
5739dbe2cd1Smartijn void
agentx_session_free(struct agentx_session * axs)57481180db9Smartijn agentx_session_free(struct agentx_session *axs)
5759dbe2cd1Smartijn {
57633598f3aSmartijn 	struct agentx_context *axc, *taxc;
577f00a771dSmartijn 	struct agentx *ax;
578f00a771dSmartijn 	int axfree;
5799dbe2cd1Smartijn 
58081180db9Smartijn 	if (axs == NULL)
58181180db9Smartijn 		return;
5829dbe2cd1Smartijn 
583f00a771dSmartijn 	ax = axs->axs_ax;
584f00a771dSmartijn 	axfree = ax->ax_free;
585f00a771dSmartijn 	ax->ax_free = 1;
586f00a771dSmartijn 
58781180db9Smartijn 	if (axs->axs_dstate == AX_DSTATE_CLOSE)
58881180db9Smartijn 		agentx_log_axs_fatalx(axs, "%s: double free", __func__);
58981180db9Smartijn 
59081180db9Smartijn 	axs->axs_dstate = AX_DSTATE_CLOSE;
59181180db9Smartijn 
59281180db9Smartijn 	if (axs->axs_cstate == AX_CSTATE_OPEN)
59381180db9Smartijn 		(void) agentx_session_close(axs, AX_CLOSE_SHUTDOWN);
59481180db9Smartijn 
59533598f3aSmartijn 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc) {
59681180db9Smartijn 		if (axc->axc_dstate != AX_DSTATE_CLOSE)
59781180db9Smartijn 			agentx_context_free(axc);
5989dbe2cd1Smartijn 	}
59981180db9Smartijn 
600f00a771dSmartijn 	if (!axfree)
601f00a771dSmartijn 		agentx_free_finalize(ax);
60281180db9Smartijn }
60381180db9Smartijn 
60481180db9Smartijn static void
agentx_session_free_finalize(struct agentx_session * axs)60581180db9Smartijn agentx_session_free_finalize(struct agentx_session *axs)
60681180db9Smartijn {
60781180db9Smartijn 	struct agentx *ax = axs->axs_ax;
608f00a771dSmartijn 	struct agentx_context *axc, *taxc;
60981180db9Smartijn 
610f00a771dSmartijn 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
611f00a771dSmartijn 		agentx_context_free_finalize(axc);
612f00a771dSmartijn 
613f00a771dSmartijn 	if (!TAILQ_EMPTY(&(axs->axs_contexts)) ||
614f00a771dSmartijn 	    axs->axs_cstate != AX_CSTATE_CLOSE ||
615f00a771dSmartijn 	    axs->axs_dstate != AX_DSTATE_CLOSE)
616f00a771dSmartijn 		return;
61781180db9Smartijn 
61881180db9Smartijn 	TAILQ_REMOVE(&(ax->ax_sessions), axs, axs_ax_sessions);
61981180db9Smartijn 	free(axs->axs_descr.aos_string);
62081180db9Smartijn 	free(axs);
62181180db9Smartijn }
62281180db9Smartijn 
62381180db9Smartijn static void
agentx_session_reset(struct agentx_session * axs)62481180db9Smartijn agentx_session_reset(struct agentx_session *axs)
62581180db9Smartijn {
62633598f3aSmartijn 	struct agentx_context *axc, *taxc;
627f00a771dSmartijn 	struct agentx *ax = axs->axs_ax;
628f00a771dSmartijn 	int axfree = ax->ax_free;
629f00a771dSmartijn 
630f00a771dSmartijn 	ax->ax_free = 1;
63181180db9Smartijn 
63281180db9Smartijn 	axs->axs_cstate = AX_CSTATE_CLOSE;
63381180db9Smartijn 
63433598f3aSmartijn 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
63581180db9Smartijn 		agentx_context_reset(axc);
63681180db9Smartijn 
637f00a771dSmartijn 	if (!axfree)
638f00a771dSmartijn 		agentx_free_finalize(ax);
63981180db9Smartijn }
64081180db9Smartijn 
64181180db9Smartijn struct agentx_context *
agentx_context(struct agentx_session * axs,const char * name)64281180db9Smartijn agentx_context(struct agentx_session *axs, const char *name)
64381180db9Smartijn {
64481180db9Smartijn 	struct agentx_context *axc;
64581180db9Smartijn 
64681180db9Smartijn 	if (axs->axs_dstate == AX_DSTATE_CLOSE)
64781180db9Smartijn 		agentx_log_axs_fatalx(axs, "%s: use after free", __func__);
64881180db9Smartijn 
64981180db9Smartijn 	if ((axc = calloc(1, sizeof(*axc))) == NULL)
65081180db9Smartijn 		return NULL;
65181180db9Smartijn 
65281180db9Smartijn 	axc->axc_axs = axs;
65381180db9Smartijn 	axc->axc_name_default = (name == NULL);
65481180db9Smartijn 	if (name != NULL) {
65581180db9Smartijn 		axc->axc_name.aos_string = (unsigned char *)strdup(name);
65681180db9Smartijn 		if (axc->axc_name.aos_string == NULL) {
65781180db9Smartijn 			free(axc);
65881180db9Smartijn 			return NULL;
65981180db9Smartijn 		}
66081180db9Smartijn 		axc->axc_name.aos_slen = strlen(name);
66181180db9Smartijn 	}
66281180db9Smartijn 	axc->axc_cstate = axs->axs_cstate == AX_CSTATE_OPEN ?
66381180db9Smartijn 	    AX_CSTATE_OPEN : AX_CSTATE_CLOSE;
66481180db9Smartijn 	axc->axc_dstate = AX_DSTATE_OPEN;
66581180db9Smartijn 	TAILQ_INIT(&(axc->axc_agentcaps));
66681180db9Smartijn 	TAILQ_INIT(&(axc->axc_regions));
66781180db9Smartijn 
66881180db9Smartijn 	TAILQ_INSERT_HEAD(&(axs->axs_contexts), axc, axc_axs_contexts);
66981180db9Smartijn 
67081180db9Smartijn 	return axc;
67181180db9Smartijn }
67281180db9Smartijn 
67367d8ab44Smartijn static int
agentx_context_retry(struct agentx_context * axc)67467d8ab44Smartijn agentx_context_retry(struct agentx_context *axc)
67567d8ab44Smartijn {
67667d8ab44Smartijn 	struct agentx_agentcaps *axa;
67767d8ab44Smartijn 	struct agentx_region *axr;
67867d8ab44Smartijn 
67967d8ab44Smartijn #ifdef AX_DEBUG
68067d8ab44Smartijn 	if (axc->axc_cstate != AX_CSTATE_OPEN)
68167d8ab44Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected retry", __func__);
68267d8ab44Smartijn #endif
68367d8ab44Smartijn 
68467d8ab44Smartijn 	TAILQ_FOREACH(axa, &(axc->axc_agentcaps), axa_axc_agentcaps) {
68567d8ab44Smartijn 		if (axa->axa_cstate == AX_CSTATE_CLOSE) {
68667d8ab44Smartijn 			if (agentx_agentcaps_start(axa) == -1)
68767d8ab44Smartijn 				return -1;
68867d8ab44Smartijn 		}
68967d8ab44Smartijn 	}
69067d8ab44Smartijn 	TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
69167d8ab44Smartijn 		if (axr->axr_cstate == AX_CSTATE_OPEN) {
69267d8ab44Smartijn 			if (agentx_region_retry(axr) == -1)
69367d8ab44Smartijn 				return -1;
69467d8ab44Smartijn 		} else if (axr->axr_cstate == AX_CSTATE_CLOSE) {
69567d8ab44Smartijn 			if (agentx_region_start(axr) == -1)
69667d8ab44Smartijn 				return -1;
69767d8ab44Smartijn 		}
69867d8ab44Smartijn 	}
69967d8ab44Smartijn 	return 0;
70067d8ab44Smartijn }
70167d8ab44Smartijn 
70267d8ab44Smartijn 
70381180db9Smartijn static void
agentx_context_start(struct agentx_context * axc)70481180db9Smartijn agentx_context_start(struct agentx_context *axc)
70581180db9Smartijn {
70681180db9Smartijn 	struct agentx_agentcaps *axa;
70781180db9Smartijn 	struct agentx_region *axr;
70881180db9Smartijn 
70981180db9Smartijn #ifdef AX_DEBUG
71081180db9Smartijn 	if (axc->axc_cstate != AX_CSTATE_CLOSE)
71181180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected context start",
71281180db9Smartijn 		    __func__);
71381180db9Smartijn #endif
71481180db9Smartijn 	axc->axc_cstate = AX_CSTATE_OPEN;
71581180db9Smartijn 
71681180db9Smartijn 	TAILQ_FOREACH(axa, &(axc->axc_agentcaps), axa_axc_agentcaps) {
71781180db9Smartijn 		if (agentx_agentcaps_start(axa) == -1)
71881180db9Smartijn 			return;
71981180db9Smartijn 	}
72081180db9Smartijn 	TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
72181180db9Smartijn 		if (agentx_region_start(axr) == -1)
72281180db9Smartijn 			return;
72381180db9Smartijn 	}
72481180db9Smartijn }
72581180db9Smartijn 
72681180db9Smartijn uint32_t
agentx_context_uptime(struct agentx_context * axc)72781180db9Smartijn agentx_context_uptime(struct agentx_context *axc)
72881180db9Smartijn {
72981180db9Smartijn 	struct timespec cur, res;
73081180db9Smartijn 
73181180db9Smartijn 	if (axc->axc_sysuptimespec.tv_sec == 0 &&
73281180db9Smartijn 	    axc->axc_sysuptimespec.tv_nsec == 0)
73381180db9Smartijn 		return 0;
73481180db9Smartijn 
73581180db9Smartijn 	(void) clock_gettime(CLOCK_MONOTONIC, &cur);
73681180db9Smartijn 
73781180db9Smartijn 	timespecsub(&cur, &(axc->axc_sysuptimespec), &res);
73881180db9Smartijn 
73981180db9Smartijn 	return axc->axc_sysuptime +
74081180db9Smartijn 	    (uint32_t) ((res.tv_sec * 100) + (res.tv_nsec / 10000000));
74181180db9Smartijn }
74281180db9Smartijn 
74381180db9Smartijn struct agentx_object *
agentx_context_object_find(struct agentx_context * axc,const uint32_t oid[],size_t oidlen,int active,int instance)74481180db9Smartijn agentx_context_object_find(struct agentx_context *axc,
74581180db9Smartijn     const uint32_t oid[], size_t oidlen, int active, int instance)
74681180db9Smartijn {
74781180db9Smartijn 	struct agentx_object *axo, axo_search;
7489c70cf54Smartijn 	const char *errstr;
74981180db9Smartijn 
7509c70cf54Smartijn 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
7519c70cf54Smartijn 		if (oidlen > AGENTX_OID_MIN_LEN) {
7529c70cf54Smartijn #ifdef AX_DEBUG
7539c70cf54Smartijn 			agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
7549c70cf54Smartijn #else
7559c70cf54Smartijn 			agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
7569c70cf54Smartijn 			return NULL;
7579c70cf54Smartijn 		}
7589c70cf54Smartijn #endif
7599c70cf54Smartijn 		if (oidlen == 1)
7609c70cf54Smartijn 			axo_search.axo_oid.aoi_id[0] = oid[0];
76181180db9Smartijn 		axo_search.axo_oid.aoi_idlen = oidlen;
7629c70cf54Smartijn 	}
76381180db9Smartijn 
76481180db9Smartijn 	axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
76581180db9Smartijn 	while (axo == NULL && !instance && axo_search.axo_oid.aoi_idlen > 0) {
76681180db9Smartijn 		axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
76781180db9Smartijn 		axo_search.axo_oid.aoi_idlen--;
76881180db9Smartijn 	}
76981180db9Smartijn 	if (active && axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
77081180db9Smartijn 		return NULL;
77181180db9Smartijn 	return axo;
77281180db9Smartijn }
77381180db9Smartijn 
77481180db9Smartijn struct agentx_object *
77581180db9Smartijn agentx_context_object_nfind(struct agentx_context *axc,
77681180db9Smartijn     const uint32_t oid[], size_t oidlen, int active, int inclusive)
77781180db9Smartijn {
77881180db9Smartijn 	struct agentx_object *axo, axo_search;
7799c70cf54Smartijn 	const char *errstr;
78081180db9Smartijn 
7819c70cf54Smartijn 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
7829c70cf54Smartijn 		if (oidlen > AGENTX_OID_MIN_LEN) {
7839c70cf54Smartijn #ifdef AX_DEBUG
7849c70cf54Smartijn 			agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
7859c70cf54Smartijn #else
7869c70cf54Smartijn 			agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
7879c70cf54Smartijn 			return NULL;
7889c70cf54Smartijn #endif
7899c70cf54Smartijn 		}
7909c70cf54Smartijn 		if (oidlen == 1)
7919c70cf54Smartijn 			axo_search.axo_oid.aoi_id[0] = oid[0];
79281180db9Smartijn 		axo_search.axo_oid.aoi_idlen = oidlen;
7939c70cf54Smartijn 	}
79481180db9Smartijn 
79581180db9Smartijn 	axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
79681180db9Smartijn 	if (!inclusive && axo != NULL &&
797647ce534Smartijn 	    ax_oid_cmp(&(axo->axo_oid), &(axo_search.axo_oid)) <= 0) {
79881180db9Smartijn 		axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
79981180db9Smartijn 	}
80081180db9Smartijn 
80181180db9Smartijn 	while (active && axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
80281180db9Smartijn 		axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
80381180db9Smartijn 	return axo;
8049dbe2cd1Smartijn }
8059dbe2cd1Smartijn 
8069dbe2cd1Smartijn void
80781180db9Smartijn agentx_context_free(struct agentx_context *axc)
8089dbe2cd1Smartijn {
80933598f3aSmartijn 	struct agentx_agentcaps *axa, *taxa;
81033598f3aSmartijn 	struct agentx_region *axr, *taxr;
81181180db9Smartijn 
81281180db9Smartijn 	if (axc == NULL)
81381180db9Smartijn 		return;
81481180db9Smartijn 
81581180db9Smartijn #ifdef AX_DEBUG
81681180db9Smartijn 	if (axc->axc_dstate == AX_DSTATE_CLOSE)
81781180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: double free", __func__);
81881180db9Smartijn #endif
81981180db9Smartijn 	axc->axc_dstate = AX_DSTATE_CLOSE;
82081180db9Smartijn 
82181180db9Smartijn 	TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps,
82233598f3aSmartijn 	    taxa) {
82381180db9Smartijn 		if (axa->axa_dstate != AX_DSTATE_CLOSE)
82481180db9Smartijn 			agentx_agentcaps_free(axa);
82581180db9Smartijn 	}
82633598f3aSmartijn 	TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr) {
82781180db9Smartijn 		if (axr->axr_dstate != AX_DSTATE_CLOSE)
82881180db9Smartijn 			agentx_region_free(axr);
8299dbe2cd1Smartijn 	}
8309dbe2cd1Smartijn }
8319dbe2cd1Smartijn 
83281180db9Smartijn static void
83381180db9Smartijn agentx_context_free_finalize(struct agentx_context *axc)
8349dbe2cd1Smartijn {
83581180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
836f00a771dSmartijn 	struct agentx_region *axr, *taxr;
837f00a771dSmartijn 	struct agentx_agentcaps *axa, *taxa;
83881180db9Smartijn 
839f00a771dSmartijn 	TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, taxa)
840f00a771dSmartijn 		agentx_agentcaps_free_finalize(axa);
841f00a771dSmartijn 	TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr)
842f00a771dSmartijn 		agentx_region_free_finalize(axr);
843f00a771dSmartijn 
84481180db9Smartijn 	if (!TAILQ_EMPTY(&(axc->axc_regions)) ||
845f00a771dSmartijn 	    !TAILQ_EMPTY(&(axc->axc_agentcaps)) ||
846f00a771dSmartijn 	    axc->axc_cstate != AX_CSTATE_CLOSE ||
847f00a771dSmartijn 	    axc->axc_dstate != AX_DSTATE_CLOSE)
84881180db9Smartijn 		return;
849f00a771dSmartijn 
85081180db9Smartijn 	TAILQ_REMOVE(&(axs->axs_contexts), axc, axc_axs_contexts);
85181180db9Smartijn 	free(axc->axc_name.aos_string);
85281180db9Smartijn 	free(axc);
8539dbe2cd1Smartijn }
8549dbe2cd1Smartijn 
85581180db9Smartijn static void
85681180db9Smartijn agentx_context_reset(struct agentx_context *axc)
8579dbe2cd1Smartijn {
85833598f3aSmartijn 	struct agentx_agentcaps *axa, *taxa;
85933598f3aSmartijn 	struct agentx_region *axr, *taxr;
860f00a771dSmartijn 	struct agentx *ax = axc->axc_axs->axs_ax;
861f00a771dSmartijn 	int axfree = ax->ax_free;
862f00a771dSmartijn 
863f00a771dSmartijn 	ax->ax_free = 1;
86481180db9Smartijn 
86581180db9Smartijn 	axc->axc_cstate = AX_CSTATE_CLOSE;
86681180db9Smartijn 	axc->axc_sysuptimespec.tv_sec = 0;
86781180db9Smartijn 	axc->axc_sysuptimespec.tv_nsec = 0;
86881180db9Smartijn 
86933598f3aSmartijn 	TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, taxa)
87081180db9Smartijn 		agentx_agentcaps_reset(axa);
87133598f3aSmartijn 	TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr)
87281180db9Smartijn 		agentx_region_reset(axr);
87381180db9Smartijn 
874f00a771dSmartijn 	if (!axfree)
875f00a771dSmartijn 		agentx_free_finalize(ax);
8769dbe2cd1Smartijn }
8779dbe2cd1Smartijn 
87881180db9Smartijn struct agentx_agentcaps *
87981180db9Smartijn agentx_agentcaps(struct agentx_context *axc, uint32_t oid[],
88081180db9Smartijn     size_t oidlen, const char *descr)
8819dbe2cd1Smartijn {
88281180db9Smartijn 	struct agentx_agentcaps *axa;
8839c70cf54Smartijn 	const char *errstr;
8849dbe2cd1Smartijn 
88581180db9Smartijn 	if (axc->axc_dstate == AX_DSTATE_CLOSE)
88681180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: use after free", __func__);
8879dbe2cd1Smartijn 
88881180db9Smartijn 	if ((axa = calloc(1, sizeof(*axa))) == NULL)
88981180db9Smartijn 		return NULL;
8909dbe2cd1Smartijn 
89181180db9Smartijn 	axa->axa_axc = axc;
8929c70cf54Smartijn 	if (agentx_oidfill(&(axa->axa_oid), oid, oidlen, &errstr) == -1) {
8939c70cf54Smartijn #ifdef AX_DEBUG
8949c70cf54Smartijn 		agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
8959c70cf54Smartijn #else
8969c70cf54Smartijn 		agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
8979c70cf54Smartijn 		return NULL;
8989c70cf54Smartijn #endif
8999c70cf54Smartijn 	}
90081180db9Smartijn 	axa->axa_descr.aos_string = (unsigned char *)strdup(descr);
90181180db9Smartijn 	if (axa->axa_descr.aos_string == NULL) {
90281180db9Smartijn 		free(axa);
90381180db9Smartijn 		return NULL;
90481180db9Smartijn 	}
90581180db9Smartijn 	axa->axa_descr.aos_slen = strlen(descr);
90681180db9Smartijn 	axa->axa_cstate = AX_CSTATE_CLOSE;
90781180db9Smartijn 	axa->axa_dstate = AX_DSTATE_OPEN;
9089dbe2cd1Smartijn 
90981180db9Smartijn 	TAILQ_INSERT_TAIL(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
9109dbe2cd1Smartijn 
91181180db9Smartijn 	if (axc->axc_cstate == AX_CSTATE_OPEN)
91281180db9Smartijn 		agentx_agentcaps_start(axa);
9139dbe2cd1Smartijn 
91481180db9Smartijn 	return axa;
9159dbe2cd1Smartijn }
9169dbe2cd1Smartijn 
9179dbe2cd1Smartijn static int
91881180db9Smartijn agentx_agentcaps_start(struct agentx_agentcaps *axa)
9199dbe2cd1Smartijn {
92081180db9Smartijn 	struct agentx_context *axc = axa->axa_axc;
92181180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
92281180db9Smartijn 	struct agentx *ax = axs->axs_ax;
92381180db9Smartijn 	uint32_t packetid;
92481180db9Smartijn 
92581180db9Smartijn #ifdef AX_DEBUG
92681180db9Smartijn 	if (axc->axc_cstate != AX_CSTATE_OPEN ||
92781180db9Smartijn 	    axa->axa_cstate != AX_CSTATE_CLOSE ||
92881180db9Smartijn 	    axa->axa_dstate != AX_DSTATE_OPEN)
92981180db9Smartijn 		agentx_log_axc_fatalx(axc,
93081180db9Smartijn 		    "%s: unexpected region registration", __func__);
93181180db9Smartijn #endif
93281180db9Smartijn 
93381180db9Smartijn 	packetid = ax_addagentcaps(ax->ax_ax, axs->axs_id,
93481180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), &(axa->axa_oid), &(axa->axa_descr));
93581180db9Smartijn 	if (packetid == 0) {
93681180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
93781180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_ADDAGENTCAPS));
93881180db9Smartijn 		agentx_reset(ax);
9399dbe2cd1Smartijn 		return -1;
9409dbe2cd1Smartijn 	}
94181180db9Smartijn 	agentx_log_axc_info(axc, "agentcaps %s: opening",
94281180db9Smartijn 	    ax_oid2string(&(axa->axa_oid)));
94381180db9Smartijn 	axa->axa_cstate = AX_CSTATE_WAITOPEN;
94481180db9Smartijn 	return agentx_request(ax, packetid, agentx_agentcaps_finalize,
94581180db9Smartijn 	    axa);
94681180db9Smartijn }
9479dbe2cd1Smartijn 
94881180db9Smartijn static int
94981180db9Smartijn agentx_agentcaps_finalize(struct ax_pdu *pdu, void *cookie)
95081180db9Smartijn {
95181180db9Smartijn 	struct agentx_agentcaps *axa = cookie;
95281180db9Smartijn 	struct agentx_context *axc = axa->axa_axc;
95381180db9Smartijn 
95481180db9Smartijn #ifdef AX_DEBUG
95581180db9Smartijn 	if (axa->axa_cstate != AX_CSTATE_WAITOPEN)
95681180db9Smartijn 		agentx_log_axc_fatalx(axc,
95781180db9Smartijn 		    "%s: not expecting agentcaps open", __func__);
95881180db9Smartijn #endif
95981180db9Smartijn 
96081180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
96181180db9Smartijn 		/* Agentcaps failing is nothing too serious */
96281180db9Smartijn 		agentx_log_axc_warn(axc, "agentcaps %s: %s",
96381180db9Smartijn 		    ax_oid2string(&(axa->axa_oid)),
96481180db9Smartijn 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
96581180db9Smartijn 		axa->axa_cstate = AX_CSTATE_CLOSE;
96681180db9Smartijn 		return 0;
9679dbe2cd1Smartijn 	}
9689dbe2cd1Smartijn 
96981180db9Smartijn 	axa->axa_cstate = AX_CSTATE_OPEN;
97081180db9Smartijn 
97181180db9Smartijn 	agentx_log_axc_info(axc, "agentcaps %s: open",
97281180db9Smartijn 	    ax_oid2string(&(axa->axa_oid)));
97381180db9Smartijn 
97481180db9Smartijn 	if (axa->axa_dstate == AX_DSTATE_CLOSE)
97581180db9Smartijn 		agentx_agentcaps_close(axa);
97681180db9Smartijn 
9779dbe2cd1Smartijn 	return 0;
9789dbe2cd1Smartijn }
9799dbe2cd1Smartijn 
98081180db9Smartijn static int
98181180db9Smartijn agentx_agentcaps_close(struct agentx_agentcaps *axa)
9829dbe2cd1Smartijn {
98381180db9Smartijn 	struct agentx_context *axc = axa->axa_axc;
98481180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
98581180db9Smartijn 	struct agentx *ax = axs->axs_ax;
98681180db9Smartijn 	uint32_t packetid;
9879dbe2cd1Smartijn 
98881180db9Smartijn #ifdef AX_DEBUG
98981180db9Smartijn 	if (axa->axa_cstate != AX_CSTATE_OPEN)
99081180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected agentcaps close",
99181180db9Smartijn 		    __func__);
99281180db9Smartijn #endif
99381180db9Smartijn 
99481180db9Smartijn 	axa->axa_cstate = AX_CSTATE_WAITCLOSE;
99581180db9Smartijn 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
9969dbe2cd1Smartijn 		return 0;
99781180db9Smartijn 
99881180db9Smartijn 	packetid = ax_removeagentcaps(ax->ax_ax, axs->axs_id,
99981180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), &(axa->axa_oid));
100081180db9Smartijn 	if (packetid == 0) {
100181180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
100281180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_REMOVEAGENTCAPS));
100381180db9Smartijn 		agentx_reset(ax);
100481180db9Smartijn 		return -1;
10059dbe2cd1Smartijn 	}
100681180db9Smartijn 	agentx_log_axc_info(axc, "agentcaps %s: closing",
100781180db9Smartijn 	    ax_oid2string(&(axa->axa_oid)));
100881180db9Smartijn 	return agentx_request(ax, packetid,
100981180db9Smartijn 	    agentx_agentcaps_close_finalize, axa);
101081180db9Smartijn }
101181180db9Smartijn 
101281180db9Smartijn static int
101381180db9Smartijn agentx_agentcaps_close_finalize(struct ax_pdu *pdu, void *cookie)
101481180db9Smartijn {
101581180db9Smartijn 	struct agentx_agentcaps *axa = cookie;
101681180db9Smartijn 	struct agentx_context *axc = axa->axa_axc;
101781180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
101881180db9Smartijn 	struct agentx *ax = axs->axs_ax;
1019f00a771dSmartijn 	int axfree = ax->ax_free;
102081180db9Smartijn 
102181180db9Smartijn #ifdef AX_DEBUG
102281180db9Smartijn 	if (axa->axa_cstate != AX_CSTATE_WAITCLOSE)
102381180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected agentcaps close",
102481180db9Smartijn 		    __func__);
102581180db9Smartijn #endif
102681180db9Smartijn 
102781180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
102881180db9Smartijn 		agentx_log_axc_warnx(axc, "agentcaps %s: %s",
102981180db9Smartijn 		    ax_oid2string(&(axa->axa_oid)),
103081180db9Smartijn 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
103181180db9Smartijn 		agentx_reset(ax);
103281180db9Smartijn 		return -1;
103381180db9Smartijn 	}
103481180db9Smartijn 
103581180db9Smartijn 	axa->axa_cstate = AX_CSTATE_CLOSE;
1036f00a771dSmartijn 	ax->ax_free = 1;
103781180db9Smartijn 
103881180db9Smartijn 	agentx_log_axc_info(axc, "agentcaps %s: closed",
103981180db9Smartijn 	    ax_oid2string(&(axa->axa_oid)));
104081180db9Smartijn 
1041f00a771dSmartijn 	if (axc->axc_cstate == AX_CSTATE_OPEN &&
1042f00a771dSmartijn 	    axa->axa_dstate == AX_DSTATE_OPEN)
1043f00a771dSmartijn 		agentx_agentcaps_start(axa);
1044f00a771dSmartijn 
1045f00a771dSmartijn 	if (!axfree)
1046f00a771dSmartijn 		agentx_free_finalize(ax);
104781180db9Smartijn 	return 0;
104881180db9Smartijn }
104981180db9Smartijn 
105081180db9Smartijn void
105181180db9Smartijn agentx_agentcaps_free(struct agentx_agentcaps *axa)
105281180db9Smartijn {
1053f00a771dSmartijn 	struct agentx *ax = axa->axa_axc->axc_axs->axs_ax;
1054f00a771dSmartijn 	int axfree;
1055f00a771dSmartijn 
105681180db9Smartijn 	if (axa == NULL)
105781180db9Smartijn 		return;
105881180db9Smartijn 
1059f00a771dSmartijn 	axfree = ax->ax_free;
1060f00a771dSmartijn 	ax->ax_free = 1;
1061f00a771dSmartijn 
106281180db9Smartijn 	if (axa->axa_dstate == AX_DSTATE_CLOSE)
106381180db9Smartijn 		agentx_log_axc_fatalx(axa->axa_axc, "%s: double free",
106481180db9Smartijn 		    __func__);
106581180db9Smartijn 
106681180db9Smartijn 	axa->axa_dstate = AX_DSTATE_CLOSE;
106781180db9Smartijn 
1068f00a771dSmartijn 	if (axa->axa_cstate == AX_CSTATE_OPEN)
1069f00a771dSmartijn 		agentx_agentcaps_close(axa);
107081180db9Smartijn 
1071f00a771dSmartijn 	if (!axfree)
1072f00a771dSmartijn 		agentx_free_finalize(ax);
107381180db9Smartijn }
107481180db9Smartijn 
107581180db9Smartijn static void
107681180db9Smartijn agentx_agentcaps_free_finalize(struct agentx_agentcaps *axa)
107781180db9Smartijn {
107881180db9Smartijn 	struct agentx_context *axc = axa->axa_axc;
107981180db9Smartijn 
108081180db9Smartijn 	if (axa->axa_dstate != AX_DSTATE_CLOSE ||
108181180db9Smartijn 	    axa->axa_cstate != AX_CSTATE_CLOSE)
1082f00a771dSmartijn 		return;
108381180db9Smartijn 
108481180db9Smartijn 	TAILQ_REMOVE(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
108581180db9Smartijn 	free(axa->axa_descr.aos_string);
108681180db9Smartijn 	free(axa);
108781180db9Smartijn }
108881180db9Smartijn 
108981180db9Smartijn static void
109081180db9Smartijn agentx_agentcaps_reset(struct agentx_agentcaps *axa)
109181180db9Smartijn {
1092f00a771dSmartijn 	struct agentx *ax = axa->axa_axc->axc_axs->axs_ax;
1093f00a771dSmartijn 
109481180db9Smartijn 	axa->axa_cstate = AX_CSTATE_CLOSE;
109581180db9Smartijn 
1096f00a771dSmartijn 	if (!ax->ax_free)
1097f00a771dSmartijn 		agentx_free_finalize(ax);
109881180db9Smartijn }
109981180db9Smartijn 
110081180db9Smartijn struct agentx_region *
110181180db9Smartijn agentx_region(struct agentx_context *axc, uint32_t oid[],
110281180db9Smartijn     size_t oidlen, uint8_t timeout)
110381180db9Smartijn {
110481180db9Smartijn 	struct agentx_region *axr;
110581180db9Smartijn 	struct ax_oid tmpoid;
11069c70cf54Smartijn 	const char *errstr;
110781180db9Smartijn 
110881180db9Smartijn 	if (axc->axc_dstate == AX_DSTATE_CLOSE)
110981180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: use after free", __func__);
111081180db9Smartijn 
11119c70cf54Smartijn 	if (agentx_oidfill(&tmpoid, oid, oidlen, &errstr) == -1) {
11129c70cf54Smartijn #ifdef AX_DEBUG
11139c70cf54Smartijn 		agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
11149c70cf54Smartijn #else
11159c70cf54Smartijn 		return NULL;
11169c70cf54Smartijn #endif
11179c70cf54Smartijn 
11189c70cf54Smartijn 	}
111981180db9Smartijn 	TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
112081180db9Smartijn 		if (ax_oid_cmp(&(axr->axr_oid), &tmpoid) == 0) {
112181180db9Smartijn #ifdef AX_DEBUG
112281180db9Smartijn 			agentx_log_axc_fatalx(axc,
112381180db9Smartijn 			    "%s: duplicate region registration", __func__);
112481180db9Smartijn #else
112581180db9Smartijn 			errno = EINVAL;
112681180db9Smartijn 			return NULL;
112781180db9Smartijn #endif
112881180db9Smartijn 		}
112981180db9Smartijn 	}
113081180db9Smartijn 
113181180db9Smartijn 	if ((axr = calloc(1, sizeof(*axr))) == NULL)
113281180db9Smartijn 		return NULL;
113381180db9Smartijn 
113481180db9Smartijn 	axr->axr_axc = axc;
113581180db9Smartijn 	axr->axr_timeout = timeout;
113681180db9Smartijn 	axr->axr_priority = AX_PRIORITY_DEFAULT;
113781180db9Smartijn 	bcopy(&tmpoid, &(axr->axr_oid), sizeof(axr->axr_oid));
113881180db9Smartijn 	axr->axr_cstate = AX_CSTATE_CLOSE;
113981180db9Smartijn 	axr->axr_dstate = AX_DSTATE_OPEN;
114081180db9Smartijn 	TAILQ_INIT(&(axr->axr_indices));
114181180db9Smartijn 	TAILQ_INIT(&(axr->axr_objects));
114281180db9Smartijn 
114381180db9Smartijn 	TAILQ_INSERT_HEAD(&(axc->axc_regions), axr, axr_axc_regions);
114481180db9Smartijn 
114581180db9Smartijn 	if (axc->axc_cstate == AX_CSTATE_OPEN)
114681180db9Smartijn 		(void) agentx_region_start(axr);
114781180db9Smartijn 
114881180db9Smartijn 	return axr;
114981180db9Smartijn }
115081180db9Smartijn 
115181180db9Smartijn static int
115267d8ab44Smartijn agentx_region_retry(struct agentx_region *axr)
115367d8ab44Smartijn {
115467d8ab44Smartijn 	struct agentx_index *axi;
115567d8ab44Smartijn 	struct agentx_object *axo;
115667d8ab44Smartijn 
115767d8ab44Smartijn #ifdef AX_DEBUG
115867d8ab44Smartijn 	if (axr->axr_cstate != AX_CSTATE_OPEN)
115967d8ab44Smartijn 		agentx_log_axc_fatalx(axr->axr_axc,
116067d8ab44Smartijn 		    "%s: unexpected retry", __func__);
116167d8ab44Smartijn #endif
116267d8ab44Smartijn 
116367d8ab44Smartijn 	TAILQ_FOREACH(axi, &(axr->axr_indices), axi_axr_indices) {
116467d8ab44Smartijn 		if (axi->axi_cstate == AX_CSTATE_CLOSE) {
116567d8ab44Smartijn 			if (agentx_index_start(axi) == -1)
116667d8ab44Smartijn 				return -1;
116767d8ab44Smartijn 		}
116867d8ab44Smartijn 	}
116967d8ab44Smartijn 	TAILQ_FOREACH(axo, &(axr->axr_objects), axo_axr_objects) {
117067d8ab44Smartijn 		if (axo->axo_cstate == AX_CSTATE_CLOSE) {
117167d8ab44Smartijn 			if (agentx_object_start(axo) == -1)
117267d8ab44Smartijn 				return -1;
117367d8ab44Smartijn 		}
117467d8ab44Smartijn 	}
117567d8ab44Smartijn 	return 0;
117667d8ab44Smartijn }
117767d8ab44Smartijn 
117867d8ab44Smartijn static int
117981180db9Smartijn agentx_region_start(struct agentx_region *axr)
118081180db9Smartijn {
118181180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
118281180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
118381180db9Smartijn 	struct agentx *ax = axs->axs_ax;
118481180db9Smartijn 	uint32_t packetid;
118581180db9Smartijn 
118681180db9Smartijn #ifdef AX_DEBUG
118781180db9Smartijn 	if (axc->axc_cstate != AX_CSTATE_OPEN ||
118881180db9Smartijn 	    axr->axr_cstate != AX_CSTATE_CLOSE ||
118981180db9Smartijn 	    axr->axr_dstate != AX_DSTATE_OPEN)
119081180db9Smartijn 		agentx_log_axc_fatalx(axc,
119181180db9Smartijn 		    "%s: unexpected region registration", __func__);
119281180db9Smartijn #endif
119381180db9Smartijn 
119481180db9Smartijn 	packetid = ax_register(ax->ax_ax, 0, axs->axs_id,
119581180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), axr->axr_timeout, axr->axr_priority,
119681180db9Smartijn 	    0, &(axr->axr_oid), 0);
119781180db9Smartijn 	if (packetid == 0) {
119881180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
119981180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_REGISTER));
120081180db9Smartijn 		agentx_reset(ax);
120181180db9Smartijn 		return -1;
120281180db9Smartijn 	}
120381180db9Smartijn 	agentx_log_axc_info(axc, "region %s: opening",
120481180db9Smartijn 	    ax_oid2string(&(axr->axr_oid)));
120581180db9Smartijn 	axr->axr_cstate = AX_CSTATE_WAITOPEN;
120681180db9Smartijn 	return agentx_request(ax, packetid, agentx_region_finalize, axr);
120781180db9Smartijn }
120881180db9Smartijn 
120981180db9Smartijn static int
121081180db9Smartijn agentx_region_finalize(struct ax_pdu *pdu, void *cookie)
121181180db9Smartijn {
121281180db9Smartijn 	struct agentx_region *axr = cookie;
121381180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
121481180db9Smartijn 	struct agentx_index *axi;
121581180db9Smartijn 	struct agentx_object *axo;
121681180db9Smartijn 
121781180db9Smartijn #ifdef AX_DEBUG
121881180db9Smartijn 	if (axr->axr_cstate != AX_CSTATE_WAITOPEN)
121981180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: not expecting region open",
122081180db9Smartijn 		    __func__);
122181180db9Smartijn #endif
122281180db9Smartijn 
122381180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error == AX_PDU_ERROR_NOERROR) {
122481180db9Smartijn 		axr->axr_cstate = AX_CSTATE_OPEN;
122581180db9Smartijn 		agentx_log_axc_info(axc, "region %s: open",
122681180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
122781180db9Smartijn 	} else if (pdu->ap_payload.ap_response.ap_error ==
122881180db9Smartijn 	    AX_PDU_ERROR_DUPLICATEREGISTRATION) {
122981180db9Smartijn 		axr->axr_cstate = AX_CSTATE_CLOSE;
123081180db9Smartijn 		/* Try at lower priority: first come first serve */
123181180db9Smartijn 		if ((++axr->axr_priority) != 0) {
123281180db9Smartijn 			agentx_log_axc_warnx(axc, "region %s: duplicate, "
123381180db9Smartijn 			    "reducing priority",
123481180db9Smartijn 			    ax_oid2string(&(axr->axr_oid)));
123581180db9Smartijn 			return agentx_region_start(axr);
123681180db9Smartijn 		}
123781180db9Smartijn 		agentx_log_axc_info(axc, "region %s: duplicate, can't "
123881180db9Smartijn 		    "reduce priority, ignoring",
123981180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
12408fea2aa4Smartijn 	} else {
124181180db9Smartijn 		axr->axr_cstate = AX_CSTATE_CLOSE;
124281180db9Smartijn 		agentx_log_axc_warnx(axc, "region %s: %s",
124381180db9Smartijn 		     ax_oid2string(&(axr->axr_oid)),
124481180db9Smartijn 		     ax_error2string(pdu->ap_payload.ap_response.ap_error));
124581180db9Smartijn 		return -1;
124681180db9Smartijn 	}
124781180db9Smartijn 
124881180db9Smartijn 	if (axr->axr_dstate == AX_DSTATE_CLOSE) {
124981180db9Smartijn 		if (agentx_region_close(axr) == -1)
125081180db9Smartijn 			return -1;
125181180db9Smartijn 	} else {
125281180db9Smartijn 		TAILQ_FOREACH(axi, &(axr->axr_indices), axi_axr_indices) {
125381180db9Smartijn 			if (agentx_index_start(axi) == -1)
125481180db9Smartijn 				return -1;
125581180db9Smartijn 		}
125681180db9Smartijn 		TAILQ_FOREACH(axo, &(axr->axr_objects), axo_axr_objects) {
125781180db9Smartijn 			if (agentx_object_start(axo) == -1)
125881180db9Smartijn 				return -1;
125981180db9Smartijn 		}
126081180db9Smartijn 	}
126181180db9Smartijn 	return 0;
126281180db9Smartijn }
126381180db9Smartijn 
126481180db9Smartijn static int
126581180db9Smartijn agentx_region_close(struct agentx_region *axr)
126681180db9Smartijn {
126781180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
126881180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
126981180db9Smartijn 	struct agentx *ax = axs->axs_ax;
127081180db9Smartijn 	uint32_t packetid;
127181180db9Smartijn 
127281180db9Smartijn #ifdef AX_DEBUG
127381180db9Smartijn 	if (axr->axr_cstate != AX_CSTATE_OPEN)
127481180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected region close",
127581180db9Smartijn 		    __func__);
127681180db9Smartijn #endif
127781180db9Smartijn 
127881180db9Smartijn 	axr->axr_cstate = AX_CSTATE_WAITCLOSE;
127981180db9Smartijn 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
128081180db9Smartijn 		return 0;
128181180db9Smartijn 
128281180db9Smartijn 	packetid = ax_unregister(ax->ax_ax, axs->axs_id,
128381180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), axr->axr_priority, 0, &(axr->axr_oid),
128481180db9Smartijn 	    0);
128581180db9Smartijn 	if (packetid == 0) {
128681180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
128781180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
128881180db9Smartijn 		agentx_reset(ax);
128981180db9Smartijn 		return -1;
129081180db9Smartijn 	}
129181180db9Smartijn 	agentx_log_axc_info(axc, "region %s: closing",
129281180db9Smartijn 	    ax_oid2string(&(axr->axr_oid)));
129381180db9Smartijn 	return agentx_request(ax, packetid, agentx_region_close_finalize,
129481180db9Smartijn 	    axr);
129581180db9Smartijn }
129681180db9Smartijn 
129781180db9Smartijn static int
129881180db9Smartijn agentx_region_close_finalize(struct ax_pdu *pdu, void *cookie)
129981180db9Smartijn {
130081180db9Smartijn 	struct agentx_region *axr = cookie;
130181180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
130281180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
130381180db9Smartijn 	struct agentx *ax = axs->axs_ax;
1304f00a771dSmartijn 	int axfree = ax->ax_free;
130581180db9Smartijn 
130681180db9Smartijn #ifdef AX_DEBUG
130781180db9Smartijn 	if (axr->axr_cstate != AX_CSTATE_WAITCLOSE)
130881180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected region close",
130981180db9Smartijn 		    __func__);
131081180db9Smartijn #endif
131181180db9Smartijn 
131281180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
131381180db9Smartijn 		agentx_log_axc_warnx(axc, "closing %s: %s",
131481180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)),
131581180db9Smartijn 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
131681180db9Smartijn 		agentx_reset(ax);
131781180db9Smartijn 		return -1;
131881180db9Smartijn 	}
131981180db9Smartijn 
1320f00a771dSmartijn 	ax->ax_free = 1;
132181180db9Smartijn 	axr->axr_priority = AX_PRIORITY_DEFAULT;
132281180db9Smartijn 	axr->axr_cstate = AX_CSTATE_CLOSE;
132381180db9Smartijn 
132481180db9Smartijn 	agentx_log_axc_info(axc, "region %s: closed",
132581180db9Smartijn 	    ax_oid2string(&(axr->axr_oid)));
132681180db9Smartijn 
1327f00a771dSmartijn 	if (axc->axc_cstate == AX_CSTATE_OPEN &&
1328f00a771dSmartijn 	    axr->axr_dstate == AX_DSTATE_OPEN)
1329f00a771dSmartijn 		agentx_region_start(axr);
1330f00a771dSmartijn 
1331f00a771dSmartijn 	if (!axfree)
1332f00a771dSmartijn 		agentx_free_finalize(ax);
133381180db9Smartijn 	return 0;
133481180db9Smartijn }
133581180db9Smartijn 
133681180db9Smartijn void
133781180db9Smartijn agentx_region_free(struct agentx_region *axr)
133881180db9Smartijn {
133933598f3aSmartijn 	struct agentx_index *axi, *taxi;
134033598f3aSmartijn 	struct agentx_object *axo, *taxo;
1341f00a771dSmartijn 	struct agentx *ax;
1342f00a771dSmartijn 	int axfree;
134381180db9Smartijn 
134481180db9Smartijn 	if (axr == NULL)
134581180db9Smartijn 		return;
134681180db9Smartijn 
1347f00a771dSmartijn 	ax = axr->axr_axc->axc_axs->axs_ax;
1348f00a771dSmartijn 	axfree = ax->ax_free;
1349f00a771dSmartijn 	ax->ax_free = 1;
1350f00a771dSmartijn 
135181180db9Smartijn 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
135281180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: double free",
135381180db9Smartijn 		    __func__);
135481180db9Smartijn 
135581180db9Smartijn 	axr->axr_dstate = AX_DSTATE_CLOSE;
135681180db9Smartijn 
135733598f3aSmartijn 	TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi) {
135881180db9Smartijn 		if (axi->axi_dstate != AX_DSTATE_CLOSE)
135981180db9Smartijn 			agentx_index_free(axi);
136081180db9Smartijn 	}
136181180db9Smartijn 
136233598f3aSmartijn 	TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo) {
136381180db9Smartijn 		if (axo->axo_dstate != AX_DSTATE_CLOSE)
136481180db9Smartijn 			agentx_object_free(axo);
136581180db9Smartijn 	}
136681180db9Smartijn 
1367f00a771dSmartijn 	if (axr->axr_cstate == AX_CSTATE_OPEN)
1368f00a771dSmartijn 		agentx_region_close(axr);
136981180db9Smartijn 
1370f00a771dSmartijn 	if (!axfree)
1371f00a771dSmartijn 		agentx_free_finalize(ax);
137281180db9Smartijn }
137381180db9Smartijn 
137481180db9Smartijn static void
137581180db9Smartijn agentx_region_free_finalize(struct agentx_region *axr)
137681180db9Smartijn {
137781180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
1378f00a771dSmartijn 	struct agentx_index *axi, *taxi;
1379f00a771dSmartijn 	struct agentx_object *axo, *taxo;
138081180db9Smartijn 
1381f00a771dSmartijn 	TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo)
1382f00a771dSmartijn 		agentx_object_free_finalize(axo);
1383f00a771dSmartijn 	TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi)
1384f00a771dSmartijn 		agentx_index_free_finalize(axi);
138581180db9Smartijn 
138681180db9Smartijn 	if (!TAILQ_EMPTY(&(axr->axr_indices)) ||
1387f00a771dSmartijn 	    !TAILQ_EMPTY(&(axr->axr_objects)) ||
1388f00a771dSmartijn 	    axr->axr_cstate != AX_CSTATE_CLOSE ||
1389f00a771dSmartijn 	    axr->axr_dstate != AX_DSTATE_CLOSE)
139081180db9Smartijn 		return;
139181180db9Smartijn 
139281180db9Smartijn 	TAILQ_REMOVE(&(axc->axc_regions), axr, axr_axc_regions);
139381180db9Smartijn 	free(axr);
139481180db9Smartijn }
139581180db9Smartijn 
139681180db9Smartijn static void
139781180db9Smartijn agentx_region_reset(struct agentx_region *axr)
139881180db9Smartijn {
139933598f3aSmartijn 	struct agentx_index *axi, *taxi;
140033598f3aSmartijn 	struct agentx_object *axo, *taxo;
1401f00a771dSmartijn 	struct agentx *ax = axr->axr_axc->axc_axs->axs_ax;
1402f00a771dSmartijn 	int axfree = ax->ax_free;
140381180db9Smartijn 
140481180db9Smartijn 	axr->axr_cstate = AX_CSTATE_CLOSE;
140581180db9Smartijn 	axr->axr_priority = AX_PRIORITY_DEFAULT;
1406f00a771dSmartijn 	ax->ax_free = 1;
140781180db9Smartijn 
140833598f3aSmartijn 	TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi)
140981180db9Smartijn 		agentx_index_reset(axi);
141033598f3aSmartijn 	TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo)
141181180db9Smartijn 		agentx_object_reset(axo);
141281180db9Smartijn 
1413f00a771dSmartijn 	if (!axfree)
1414f00a771dSmartijn 		agentx_free_finalize(ax);
141581180db9Smartijn }
141681180db9Smartijn 
141781180db9Smartijn struct agentx_index *
141881180db9Smartijn agentx_index_integer_new(struct agentx_region *axr, uint32_t oid[],
141981180db9Smartijn     size_t oidlen)
142081180db9Smartijn {
142181180db9Smartijn 	struct ax_varbind vb;
14229c70cf54Smartijn 	const char *errstr;
142381180db9Smartijn 
14249c70cf54Smartijn 	vb.avb_type = AX_DATA_TYPE_INTEGER;
14259c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
142681180db9Smartijn #ifdef AX_DEBUG
14279c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
142881180db9Smartijn #else
14299c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
143081180db9Smartijn 		return NULL;
143181180db9Smartijn #endif
143281180db9Smartijn 	}
14331b6ededeSmartijn 	vb.avb_data.avb_int32 = 0;
143481180db9Smartijn 
143581180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_NEW);
143681180db9Smartijn }
143781180db9Smartijn 
143881180db9Smartijn struct agentx_index *
143981180db9Smartijn agentx_index_integer_any(struct agentx_region *axr, uint32_t oid[],
144081180db9Smartijn     size_t oidlen)
144181180db9Smartijn {
144281180db9Smartijn 	struct ax_varbind vb;
14439c70cf54Smartijn 	const char *errstr;
144481180db9Smartijn 
14459c70cf54Smartijn 	vb.avb_type = AX_DATA_TYPE_INTEGER;
14469c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
144781180db9Smartijn #ifdef AX_DEBUG
14489c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
144981180db9Smartijn #else
14509c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
145181180db9Smartijn 		return NULL;
145281180db9Smartijn #endif
145381180db9Smartijn 	}
14541b6ededeSmartijn 	vb.avb_data.avb_int32 = 0;
145581180db9Smartijn 
145681180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_ANY);
145781180db9Smartijn }
145881180db9Smartijn 
145981180db9Smartijn struct agentx_index *
146081180db9Smartijn agentx_index_integer_value(struct agentx_region *axr, uint32_t oid[],
14611b6ededeSmartijn     size_t oidlen, int32_t value)
146281180db9Smartijn {
146381180db9Smartijn 	struct ax_varbind vb;
14649c70cf54Smartijn 	const char *errstr;
146581180db9Smartijn 
14661b6ededeSmartijn 	if (value < 0) {
14671b6ededeSmartijn #ifdef AX_DEBUG
14681b6ededeSmartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: value < 0", __func__);
14691b6ededeSmartijn #else
14701b6ededeSmartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: value < 0", __func__);
14711b6ededeSmartijn 		errno = EINVAL;
14721b6ededeSmartijn 		return NULL;
14731b6ededeSmartijn #endif
14741b6ededeSmartijn 	}
147581180db9Smartijn 
147681180db9Smartijn 	vb.avb_type = AX_DATA_TYPE_INTEGER;
14779c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
14789c70cf54Smartijn #ifdef AX_DEBUG
14799c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
14809c70cf54Smartijn #else
14819c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
14829c70cf54Smartijn 		return NULL;
14839c70cf54Smartijn #endif
14849c70cf54Smartijn 	}
14851b6ededeSmartijn 	vb.avb_data.avb_int32 = value;
148681180db9Smartijn 
148781180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_VALUE);
148881180db9Smartijn }
148981180db9Smartijn 
149081180db9Smartijn struct agentx_index *
149181180db9Smartijn agentx_index_integer_dynamic(struct agentx_region *axr, uint32_t oid[],
149281180db9Smartijn     size_t oidlen)
149381180db9Smartijn {
149481180db9Smartijn 	struct ax_varbind vb;
14959c70cf54Smartijn 	const char *errstr;
149681180db9Smartijn 
14979c70cf54Smartijn 	vb.avb_type = AX_DATA_TYPE_INTEGER;
14989c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
149981180db9Smartijn #ifdef AX_DEBUG
15009c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
150181180db9Smartijn #else
15029c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
150381180db9Smartijn 		return NULL;
150481180db9Smartijn #endif
150581180db9Smartijn 	}
150681180db9Smartijn 
150781180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
150881180db9Smartijn }
150981180db9Smartijn 
151081180db9Smartijn struct agentx_index *
151181180db9Smartijn agentx_index_string_dynamic(struct agentx_region *axr, uint32_t oid[],
151281180db9Smartijn     size_t oidlen)
151381180db9Smartijn {
151481180db9Smartijn 	struct ax_varbind vb;
15159c70cf54Smartijn 	const char *errstr;
151681180db9Smartijn 
15179c70cf54Smartijn 	vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
15189c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
151981180db9Smartijn #ifdef AX_DEBUG
15209c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
152181180db9Smartijn #else
15229c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
152381180db9Smartijn 		return NULL;
152481180db9Smartijn #endif
152581180db9Smartijn 	}
152681180db9Smartijn 	vb.avb_data.avb_ostring.aos_slen = 0;
152781180db9Smartijn 	vb.avb_data.avb_ostring.aos_string = NULL;
152881180db9Smartijn 
152981180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
153081180db9Smartijn }
153181180db9Smartijn 
153281180db9Smartijn struct agentx_index *
153381180db9Smartijn agentx_index_nstring_dynamic(struct agentx_region *axr, uint32_t oid[],
153481180db9Smartijn     size_t oidlen, size_t vlen)
153581180db9Smartijn {
153681180db9Smartijn 	struct ax_varbind vb;
15379c70cf54Smartijn 	const char *errstr;
153881180db9Smartijn 
153981180db9Smartijn 	if (vlen == 0 || vlen > AGENTX_OID_MAX_LEN) {
154081180db9Smartijn #ifdef AX_DEBUG
154181180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid string "
154281180db9Smartijn 		    "length: %zu\n", __func__, vlen);
154381180db9Smartijn #else
154481180db9Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid string "
154581180db9Smartijn 		    "length: %zu\n", __func__, vlen);
154681180db9Smartijn 		errno = EINVAL;
154781180db9Smartijn 		return NULL;
154881180db9Smartijn #endif
154981180db9Smartijn 	}
155081180db9Smartijn 
155181180db9Smartijn 	vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
15529c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
15539c70cf54Smartijn #ifdef AX_DEBUG
15549c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
15559c70cf54Smartijn #else
15569c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
15579c70cf54Smartijn 		return NULL;
15589c70cf54Smartijn #endif
15599c70cf54Smartijn 	}
156081180db9Smartijn 	vb.avb_data.avb_ostring.aos_slen = vlen;
156181180db9Smartijn 	vb.avb_data.avb_ostring.aos_string = NULL;
156281180db9Smartijn 
156381180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
156481180db9Smartijn }
156581180db9Smartijn 
156681180db9Smartijn struct agentx_index *
156781180db9Smartijn agentx_index_oid_dynamic(struct agentx_region *axr, uint32_t oid[],
156881180db9Smartijn     size_t oidlen)
156981180db9Smartijn {
157081180db9Smartijn 	struct ax_varbind vb;
15719c70cf54Smartijn 	const char *errstr;
157281180db9Smartijn 
15739c70cf54Smartijn 	vb.avb_type = AX_DATA_TYPE_OID;
15749c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
157581180db9Smartijn #ifdef AX_DEBUG
15769c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
157781180db9Smartijn #else
15789c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
157981180db9Smartijn 		return NULL;
158081180db9Smartijn #endif
158181180db9Smartijn 	}
158281180db9Smartijn 	vb.avb_data.avb_oid.aoi_idlen = 0;
158381180db9Smartijn 
158481180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
158581180db9Smartijn }
158681180db9Smartijn 
158781180db9Smartijn struct agentx_index *
158881180db9Smartijn agentx_index_noid_dynamic(struct agentx_region *axr, uint32_t oid[],
158981180db9Smartijn     size_t oidlen, size_t vlen)
159081180db9Smartijn {
159181180db9Smartijn 	struct ax_varbind vb;
15929c70cf54Smartijn 	const char *errstr;
159381180db9Smartijn 
15949c70cf54Smartijn 	if (vlen < AGENTX_OID_MIN_LEN || vlen > AGENTX_OID_MAX_LEN) {
159581180db9Smartijn #ifdef AX_DEBUG
159681180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid string "
159781180db9Smartijn 		    "length: %zu\n", __func__, vlen);
159881180db9Smartijn #else
159981180db9Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid string "
160081180db9Smartijn 		    "length: %zu\n", __func__, vlen);
160181180db9Smartijn 		errno = EINVAL;
160281180db9Smartijn 		return NULL;
160381180db9Smartijn #endif
160481180db9Smartijn 	}
160581180db9Smartijn 
160681180db9Smartijn 	vb.avb_type = AX_DATA_TYPE_OID;
16079c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
16089c70cf54Smartijn #ifdef AX_DEBUG
16099c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
16109c70cf54Smartijn #else
16119c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
16129c70cf54Smartijn 		return NULL;
16139c70cf54Smartijn #endif
16149c70cf54Smartijn 	}
161581180db9Smartijn 	vb.avb_data.avb_oid.aoi_idlen = vlen;
161681180db9Smartijn 
161781180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
161881180db9Smartijn }
161981180db9Smartijn 
162081180db9Smartijn struct agentx_index *
162181180db9Smartijn agentx_index_ipaddress_dynamic(struct agentx_region *axr, uint32_t oid[],
162281180db9Smartijn     size_t oidlen)
162381180db9Smartijn {
162481180db9Smartijn 	struct ax_varbind vb;
16259c70cf54Smartijn 	const char *errstr;
162681180db9Smartijn 
16279c70cf54Smartijn 	vb.avb_type = AX_DATA_TYPE_IPADDRESS;
16289c70cf54Smartijn 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
162981180db9Smartijn #ifdef AX_DEBUG
16309c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
163181180db9Smartijn #else
16329c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
163381180db9Smartijn 		return NULL;
163481180db9Smartijn #endif
163581180db9Smartijn 	}
163681180db9Smartijn 	vb.avb_data.avb_ostring.aos_string = NULL;
163781180db9Smartijn 
163881180db9Smartijn 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
163981180db9Smartijn }
164081180db9Smartijn 
164181180db9Smartijn static struct agentx_index *
164281180db9Smartijn agentx_index(struct agentx_region *axr, struct ax_varbind *vb,
164381180db9Smartijn     enum agentx_index_type type)
164481180db9Smartijn {
164581180db9Smartijn 	struct agentx_index *axi;
164681180db9Smartijn 
164781180db9Smartijn 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
164881180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
164981180db9Smartijn 		    __func__);
165081180db9Smartijn 	if (ax_oid_cmp(&(axr->axr_oid), &(vb->avb_oid)) != -2) {
165181180db9Smartijn #ifdef AX_DEBUG
165281180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: oid is not child "
165381180db9Smartijn 		    "of region %s", __func__,
165481180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)));
165581180db9Smartijn #else
165681180db9Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: oid is not child of "
165781180db9Smartijn 		    "region %s", __func__, ax_oid2string(&(vb->avb_oid)));
165881180db9Smartijn 		errno = EINVAL;
165981180db9Smartijn 		return NULL;
166081180db9Smartijn #endif
166181180db9Smartijn 	}
166281180db9Smartijn 
166381180db9Smartijn 	if ((axi = calloc(1, sizeof(*axi))) == NULL)
166481180db9Smartijn 		return NULL;
166581180db9Smartijn 
166681180db9Smartijn 	axi->axi_axr = axr;
166781180db9Smartijn 	axi->axi_type = type;
166881180db9Smartijn 	bcopy(vb, &(axi->axi_vb), sizeof(*vb));
166981180db9Smartijn 	axi->axi_cstate = AX_CSTATE_CLOSE;
167081180db9Smartijn 	axi->axi_dstate = AX_DSTATE_OPEN;
167181180db9Smartijn 	TAILQ_INSERT_HEAD(&(axr->axr_indices), axi, axi_axr_indices);
167281180db9Smartijn 
167381180db9Smartijn 	if (axr->axr_cstate == AX_CSTATE_OPEN)
167481180db9Smartijn 		agentx_index_start(axi);
167581180db9Smartijn 
167681180db9Smartijn 	return axi;
167781180db9Smartijn }
167881180db9Smartijn 
167981180db9Smartijn static int
168081180db9Smartijn agentx_index_start(struct agentx_index *axi)
168181180db9Smartijn {
168281180db9Smartijn 	struct agentx_region *axr = axi->axi_axr;
168381180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
168481180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
168581180db9Smartijn 	struct agentx *ax = axs->axs_ax;
168681180db9Smartijn 	uint32_t packetid;
168781180db9Smartijn 	int flags = 0;
168881180db9Smartijn 
168981180db9Smartijn #ifdef AX_DEBUG
169081180db9Smartijn 	if (axr->axr_cstate != AX_CSTATE_OPEN ||
169181180db9Smartijn 	    axi->axi_cstate != AX_CSTATE_CLOSE ||
169281180db9Smartijn 	    axi->axi_dstate != AX_DSTATE_OPEN)
169381180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected index allocation",
169481180db9Smartijn 		    __func__);
169581180db9Smartijn #endif
169681180db9Smartijn 
169781180db9Smartijn 	axi->axi_cstate = AX_CSTATE_WAITOPEN;
169881180db9Smartijn 
169981180db9Smartijn 	if (axi->axi_type == AXI_TYPE_NEW)
170081180db9Smartijn 		flags = AX_PDU_FLAG_NEW_INDEX;
170181180db9Smartijn 	else if (axi->axi_type == AXI_TYPE_ANY)
170281180db9Smartijn 		flags = AX_PDU_FLAG_ANY_INDEX;
170381180db9Smartijn 	else if (axi->axi_type == AXI_TYPE_DYNAMIC) {
170481180db9Smartijn 		agentx_index_finalize(NULL, axi);
170581180db9Smartijn 		return 0;
170681180db9Smartijn 	}
170781180db9Smartijn 
170881180db9Smartijn 	/* We might be able to bundle, but if we fail we'd have to reorganise */
170981180db9Smartijn 	packetid = ax_indexallocate(ax->ax_ax, flags, axs->axs_id,
171081180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
171181180db9Smartijn 	if (packetid == 0) {
171281180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
171381180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
171481180db9Smartijn 		agentx_reset(ax);
171581180db9Smartijn 		return -1;
171681180db9Smartijn 	}
171781180db9Smartijn 	if (axi->axi_type == AXI_TYPE_VALUE)
17181b6ededeSmartijn 		agentx_log_axc_info(axc, "index %s: allocating '%d'",
171981180db9Smartijn 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
17201b6ededeSmartijn 		    axi->axi_vb.avb_data.avb_int32);
172181180db9Smartijn 	else if (axi->axi_type == AXI_TYPE_ANY)
172281180db9Smartijn 		agentx_log_axc_info(axc, "index %s: allocating any index",
172381180db9Smartijn 		    ax_oid2string(&(axi->axi_vb.avb_oid)));
172481180db9Smartijn 	else if (axi->axi_type == AXI_TYPE_NEW)
172581180db9Smartijn 		agentx_log_axc_info(axc, "index %s: allocating new index",
172681180db9Smartijn 		    ax_oid2string(&(axi->axi_vb.avb_oid)));
172781180db9Smartijn 
172881180db9Smartijn 	return agentx_request(ax, packetid, agentx_index_finalize, axi);
172981180db9Smartijn }
173081180db9Smartijn 
173181180db9Smartijn static int
173281180db9Smartijn agentx_index_finalize(struct ax_pdu *pdu, void *cookie)
173381180db9Smartijn {
173481180db9Smartijn 	struct agentx_index *axi = cookie;
173581180db9Smartijn 	struct agentx_region *axr = axi->axi_axr;
173681180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
173781180db9Smartijn 	struct ax_pdu_response *resp;
173881180db9Smartijn 	size_t i;
173981180db9Smartijn 
174081180db9Smartijn #ifdef AX_DEBUG
174181180db9Smartijn 	if (axi->axi_cstate != AX_CSTATE_WAITOPEN)
174281180db9Smartijn 		agentx_log_axc_fatalx(axc,
174381180db9Smartijn 		    "%s: not expecting index allocate", __func__);
174481180db9Smartijn #endif
174581180db9Smartijn 	if (axi->axi_type == AXI_TYPE_DYNAMIC) {
174681180db9Smartijn 		axi->axi_cstate = AX_CSTATE_OPEN;
1747cb11ee67Smartijn 		goto objects_start;
174881180db9Smartijn 	}
174981180db9Smartijn 
175081180db9Smartijn 	resp = &(pdu->ap_payload.ap_response);
175181180db9Smartijn 	if (resp->ap_error != AX_PDU_ERROR_NOERROR) {
175281180db9Smartijn 		axi->axi_cstate = AX_CSTATE_CLOSE;
175381180db9Smartijn 		agentx_log_axc_warnx(axc, "index %s: %s",
175481180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)),
175581180db9Smartijn 		    ax_error2string(resp->ap_error));
175681180db9Smartijn 		return 0;
175781180db9Smartijn 	}
175881180db9Smartijn 	axi->axi_cstate = AX_CSTATE_OPEN;
175981180db9Smartijn 	if (resp->ap_nvarbind != 1) {
176081180db9Smartijn 		agentx_log_axc_warnx(axc, "index %s: unexpected number of "
176181180db9Smartijn 		    "indices", ax_oid2string(&(axr->axr_oid)));
17628fea2aa4Smartijn 		axi->axi_cstate = AX_CSTATE_CLOSE;
176381180db9Smartijn 		return -1;
176481180db9Smartijn 	}
176581180db9Smartijn 	if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
176681180db9Smartijn 		agentx_log_axc_warnx(axc, "index %s: unexpected index type",
176781180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
17688fea2aa4Smartijn 		axi->axi_cstate = AX_CSTATE_CLOSE;
176981180db9Smartijn 		return -1;
177081180db9Smartijn 	}
177181180db9Smartijn 	if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
177281180db9Smartijn 	    &(axi->axi_vb.avb_oid)) != 0) {
177381180db9Smartijn 		agentx_log_axc_warnx(axc, "index %s: unexpected oid",
177481180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
17758fea2aa4Smartijn 		axi->axi_cstate = AX_CSTATE_CLOSE;
177681180db9Smartijn 		return -1;
177781180db9Smartijn 	}
177881180db9Smartijn 
177981180db9Smartijn 	switch (axi->axi_vb.avb_type) {
178081180db9Smartijn 	case AX_DATA_TYPE_INTEGER:
178181180db9Smartijn 		if (axi->axi_type == AXI_TYPE_NEW ||
178281180db9Smartijn 		    axi->axi_type == AXI_TYPE_ANY)
17831b6ededeSmartijn 			axi->axi_vb.avb_data.avb_int32 =
17841b6ededeSmartijn 			    resp->ap_varbindlist[0].avb_data.avb_int32;
17851b6ededeSmartijn 		else if (axi->axi_vb.avb_data.avb_int32 !=
17861b6ededeSmartijn 		    resp->ap_varbindlist[0].avb_data.avb_int32) {
178781180db9Smartijn 			agentx_log_axc_warnx(axc, "index %s: unexpected "
178881180db9Smartijn 			    "index value", ax_oid2string(&(axr->axr_oid)));
17898fea2aa4Smartijn 			axi->axi_cstate = AX_CSTATE_CLOSE;
179081180db9Smartijn 			return -1;
179181180db9Smartijn 		}
17921b6ededeSmartijn 		agentx_log_axc_info(axc, "index %s: allocated '%d'",
179381180db9Smartijn 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
17941b6ededeSmartijn 		    axi->axi_vb.avb_data.avb_int32);
179581180db9Smartijn 		break;
179681180db9Smartijn 	default:
179781180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
179881180db9Smartijn 		    __func__);
179981180db9Smartijn 	}
180081180db9Smartijn 
180181180db9Smartijn 	if (axi->axi_dstate == AX_DSTATE_CLOSE)
180281180db9Smartijn 		return agentx_index_close(axi);
180381180db9Smartijn 
1804cb11ee67Smartijn  objects_start:
180581180db9Smartijn 	/* TODO Make use of range_subid register */
180681180db9Smartijn 	for (i = 0; i < axi->axi_objectlen; i++) {
180781180db9Smartijn 		if (axi->axi_object[i]->axo_dstate == AX_DSTATE_OPEN) {
180881180db9Smartijn 			if (agentx_object_start(axi->axi_object[i]) == -1)
180981180db9Smartijn 				return -1;
181081180db9Smartijn 		}
181181180db9Smartijn 	}
181281180db9Smartijn 	return 0;
181381180db9Smartijn }
181481180db9Smartijn 
181581180db9Smartijn void
181681180db9Smartijn agentx_index_free(struct agentx_index *axi)
181781180db9Smartijn {
181881180db9Smartijn 	size_t i;
181981180db9Smartijn 	struct agentx_object *axo;
1820f00a771dSmartijn 	struct agentx *ax;
1821f00a771dSmartijn 	int axfree;
182281180db9Smartijn 
182381180db9Smartijn 	if (axi == NULL)
182481180db9Smartijn 		return;
182581180db9Smartijn 
1826f00a771dSmartijn 	ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
1827f00a771dSmartijn 	axfree = ax->ax_free;
1828f00a771dSmartijn 	ax->ax_free = 1;
1829f00a771dSmartijn 
183081180db9Smartijn 	if (axi->axi_dstate == AX_DSTATE_CLOSE)
183181180db9Smartijn 		agentx_log_axc_fatalx(axi->axi_axr->axr_axc,
183281180db9Smartijn 		    "%s: double free", __func__);
183381180db9Smartijn 
183481180db9Smartijn 	/* TODO Do a range_subid unregister before freeing */
183581180db9Smartijn 	for (i = 0; i < axi->axi_objectlen; i++) {
183681180db9Smartijn 		axo = axi->axi_object[i];
183781180db9Smartijn 		if (axo->axo_dstate != AX_DSTATE_CLOSE) {
183881180db9Smartijn 			agentx_object_free(axo);
183981180db9Smartijn 			if (axi->axi_object[i] != axo)
184081180db9Smartijn 				i--;
184181180db9Smartijn 		}
184281180db9Smartijn 	}
184381180db9Smartijn 
184481180db9Smartijn 	axi->axi_dstate = AX_DSTATE_CLOSE;
184581180db9Smartijn 
184681180db9Smartijn 	if (axi->axi_cstate == AX_CSTATE_OPEN)
184781180db9Smartijn 		(void) agentx_index_close(axi);
1848f00a771dSmartijn 	if (!axfree)
1849f00a771dSmartijn 		agentx_free_finalize(ax);
185081180db9Smartijn }
185181180db9Smartijn 
185281180db9Smartijn static void
185381180db9Smartijn agentx_index_free_finalize(struct agentx_index *axi)
185481180db9Smartijn {
185581180db9Smartijn 	struct agentx_region *axr = axi->axi_axr;
185681180db9Smartijn 
1857f00a771dSmartijn 	if (axi->axi_cstate != AX_CSTATE_CLOSE ||
1858f00a771dSmartijn 	    axi->axi_dstate != AX_DSTATE_CLOSE ||
1859f00a771dSmartijn 	    axi->axi_objectlen != 0)
186081180db9Smartijn 		return;
186181180db9Smartijn 
186281180db9Smartijn 	TAILQ_REMOVE(&(axr->axr_indices), axi, axi_axr_indices);
186381180db9Smartijn 	ax_varbind_free(&(axi->axi_vb));
186481180db9Smartijn 	free(axi->axi_object);
186581180db9Smartijn 	free(axi);
186681180db9Smartijn }
186781180db9Smartijn 
186881180db9Smartijn static void
186981180db9Smartijn agentx_index_reset(struct agentx_index *axi)
187081180db9Smartijn {
1871f00a771dSmartijn 	struct agentx *ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
1872f00a771dSmartijn 
187381180db9Smartijn 	axi->axi_cstate = AX_CSTATE_CLOSE;
187481180db9Smartijn 
1875f00a771dSmartijn 	if (!ax->ax_free)
1876f00a771dSmartijn 		agentx_free_finalize(ax);
187781180db9Smartijn }
187881180db9Smartijn 
187981180db9Smartijn static int
188081180db9Smartijn agentx_index_close(struct agentx_index *axi)
188181180db9Smartijn {
188281180db9Smartijn 	struct agentx_region *axr = axi->axi_axr;
188381180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
188481180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
188581180db9Smartijn 	struct agentx *ax = axs->axs_ax;
188681180db9Smartijn 	uint32_t packetid;
188781180db9Smartijn 
188881180db9Smartijn #ifdef AX_DEBUG
188981180db9Smartijn 	if (axi->axi_cstate != AX_CSTATE_OPEN)
189081180db9Smartijn 		agentx_log_axc_fatalx(axc,
189181180db9Smartijn 		    "%s: unexpected index deallocation", __func__);
189281180db9Smartijn #endif
189381180db9Smartijn 
189481180db9Smartijn 	axi->axi_cstate = AX_CSTATE_WAITCLOSE;
189581180db9Smartijn 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
189681180db9Smartijn 		return 0;
189781180db9Smartijn 
189881180db9Smartijn 	/* We might be able to bundle, but if we fail we'd have to reorganise */
189981180db9Smartijn 	packetid = ax_indexdeallocate(ax->ax_ax, axs->axs_id,
190081180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
190181180db9Smartijn 	if (packetid == 0) {
190281180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
190381180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
190481180db9Smartijn 		agentx_reset(ax);
190581180db9Smartijn 		return -1;
190681180db9Smartijn 	}
190781180db9Smartijn 	agentx_log_axc_info(axc, "index %s: deallocating",
190881180db9Smartijn 	    ax_oid2string(&(axi->axi_vb.avb_oid)));
190981180db9Smartijn 	return agentx_request(ax, packetid, agentx_index_close_finalize,
191081180db9Smartijn 	    axi);
191181180db9Smartijn }
191281180db9Smartijn 
191381180db9Smartijn static int
191481180db9Smartijn agentx_index_close_finalize(struct ax_pdu *pdu, void *cookie)
191581180db9Smartijn {
191681180db9Smartijn 	struct agentx_index *axi = cookie;
191781180db9Smartijn 	struct agentx_region *axr = axi->axi_axr;
191881180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
191981180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
192081180db9Smartijn 	struct agentx *ax = axs->axs_ax;
192181180db9Smartijn 	struct ax_pdu_response *resp = &(pdu->ap_payload.ap_response);
1922f00a771dSmartijn 	int axfree = ax->ax_free;
192381180db9Smartijn 
192481180db9Smartijn #ifdef AX_DEBUG
192581180db9Smartijn 	if (axi->axi_cstate != AX_CSTATE_WAITCLOSE)
192681180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected indexdeallocate",
192781180db9Smartijn 		    __func__);
192881180db9Smartijn #endif
192981180db9Smartijn 
193081180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
193181180db9Smartijn 		agentx_log_axc_warnx(axc,
193281180db9Smartijn 		    "index %s: couldn't deallocate: %s",
193381180db9Smartijn 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
193481180db9Smartijn 		    ax_error2string(resp->ap_error));
193581180db9Smartijn 		agentx_reset(ax);
193681180db9Smartijn 		return -1;
193781180db9Smartijn 	}
193881180db9Smartijn 
193981180db9Smartijn 	if (resp->ap_nvarbind != 1) {
194081180db9Smartijn 		agentx_log_axc_warnx(axc,
194181180db9Smartijn 		    "index %s: unexpected number of indices",
194281180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
194381180db9Smartijn 		agentx_reset(ax);
194481180db9Smartijn 		return -1;
194581180db9Smartijn 	}
194681180db9Smartijn 	if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
194781180db9Smartijn 		agentx_log_axc_warnx(axc, "index %s: unexpected index type",
194881180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
194981180db9Smartijn 		agentx_reset(ax);
195081180db9Smartijn 		return -1;
195181180db9Smartijn 	}
195281180db9Smartijn 	if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
195381180db9Smartijn 	    &(axi->axi_vb.avb_oid)) != 0) {
195481180db9Smartijn 		agentx_log_axc_warnx(axc, "index %s: unexpected oid",
195581180db9Smartijn 		    ax_oid2string(&(axr->axr_oid)));
195681180db9Smartijn 		agentx_reset(ax);
195781180db9Smartijn 		return -1;
195881180db9Smartijn 	}
195981180db9Smartijn 	switch (axi->axi_vb.avb_type) {
196081180db9Smartijn 	case AX_DATA_TYPE_INTEGER:
19611b6ededeSmartijn 		if (axi->axi_vb.avb_data.avb_int32 !=
19621b6ededeSmartijn 		    resp->ap_varbindlist[0].avb_data.avb_int32) {
196381180db9Smartijn 			agentx_log_axc_warnx(axc,
196481180db9Smartijn 			    "index %s: unexpected index value",
196581180db9Smartijn 			    ax_oid2string(&(axr->axr_oid)));
196681180db9Smartijn 			agentx_reset(ax);
196781180db9Smartijn 			return -1;
196881180db9Smartijn 		}
196981180db9Smartijn 		break;
197081180db9Smartijn 	default:
197181180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
197281180db9Smartijn 		    __func__);
197381180db9Smartijn 	}
197481180db9Smartijn 
197581180db9Smartijn 	axi->axi_cstate = AX_CSTATE_CLOSE;
1976f00a771dSmartijn 	ax->ax_free = 1;
197781180db9Smartijn 
197881180db9Smartijn 	agentx_log_axc_info(axc, "index %s: deallocated",
197981180db9Smartijn 	    ax_oid2string(&(axi->axi_vb.avb_oid)));
198081180db9Smartijn 
1981f00a771dSmartijn 	if (axr->axr_cstate == AX_CSTATE_OPEN &&
1982f00a771dSmartijn 	    axi->axi_dstate == AX_DSTATE_OPEN)
1983f00a771dSmartijn 		agentx_index_start(axi);
1984f00a771dSmartijn 
1985f00a771dSmartijn 	if (!axfree)
1986f00a771dSmartijn 		agentx_free_finalize(ax);
198781180db9Smartijn 	return 0;
198881180db9Smartijn }
198981180db9Smartijn 
199081180db9Smartijn struct agentx_object *
199181180db9Smartijn agentx_object(struct agentx_region *axr, uint32_t oid[], size_t oidlen,
199281180db9Smartijn     struct agentx_index *axi[], size_t axilen, int implied,
199381180db9Smartijn     void (*get)(struct agentx_varbind *))
199481180db9Smartijn {
199533598f3aSmartijn 	struct agentx_object *axo, **taxo, axo_search;
199633598f3aSmartijn 	struct agentx_index *laxi;
19979c70cf54Smartijn 	const char *errstr;
199881180db9Smartijn 	int ready = 1;
199981180db9Smartijn 	size_t i, j;
200081180db9Smartijn 
200181180db9Smartijn 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
200281180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
200381180db9Smartijn 		    __func__);
200481180db9Smartijn 	if (axilen > AGENTX_OID_INDEX_MAX_LEN) {
200581180db9Smartijn #ifdef AX_DEBUG
200681180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: indexlen > %d",
200781180db9Smartijn 		    __func__, AGENTX_OID_INDEX_MAX_LEN);
200881180db9Smartijn #else
200981180db9Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: indexlen > %d",
201081180db9Smartijn 		    __func__, AGENTX_OID_INDEX_MAX_LEN);
201181180db9Smartijn 		errno = EINVAL;
201281180db9Smartijn 		return NULL;
201381180db9Smartijn #endif
201481180db9Smartijn 	}
201581180db9Smartijn 
20169c70cf54Smartijn 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
20179c70cf54Smartijn #ifdef AX_DEBUG
20189c70cf54Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
20199c70cf54Smartijn #else
20209c70cf54Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
20219c70cf54Smartijn 		return NULL;
20229c70cf54Smartijn #endif
20239c70cf54Smartijn 	}
202481180db9Smartijn 
20259dbe2cd1Smartijn 	do {
202681180db9Smartijn 		if (RB_FIND(axc_objects, &(axr->axr_axc->axc_objects),
202781180db9Smartijn 		    &axo_search) != NULL) {
202881180db9Smartijn #ifdef AX_DEBUG
202981180db9Smartijn 			agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid "
203081180db9Smartijn 			    "parent child object relationship", __func__);
203181180db9Smartijn #else
203281180db9Smartijn 			agentx_log_axc_warnx(axr->axr_axc, "%s: invalid "
203381180db9Smartijn 			    "parent child object relationship", __func__);
20349dbe2cd1Smartijn 			errno = EINVAL;
203581180db9Smartijn 			return NULL;
203681180db9Smartijn #endif
203781180db9Smartijn 		}
203881180db9Smartijn 		axo_search.axo_oid.aoi_idlen--;
203981180db9Smartijn 	} while (axo_search.axo_oid.aoi_idlen > 0);
204081180db9Smartijn 	axo_search.axo_oid.aoi_idlen = oidlen;
204181180db9Smartijn 	axo = RB_NFIND(axc_objects, &(axr->axr_axc->axc_objects), &axo_search);
204281180db9Smartijn 	if (axo != NULL &&
204381180db9Smartijn 	    ax_oid_cmp(&(axo->axo_oid), &(axo_search.axo_oid)) == 2) {
204481180db9Smartijn #ifdef AX_DEBUG
204581180db9Smartijn 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid parent "
204681180db9Smartijn 		    "child object relationship", __func__);
204781180db9Smartijn #else
204881180db9Smartijn 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid parent "
204981180db9Smartijn 		    "child object relationship", __func__);
205081180db9Smartijn 		errno = EINVAL;
205181180db9Smartijn 		return NULL;
205281180db9Smartijn #endif
205381180db9Smartijn 	}
205481180db9Smartijn 	if (implied == 1) {
205533598f3aSmartijn 		laxi = axi[axilen - 1];
205633598f3aSmartijn 		if (laxi->axi_vb.avb_type == AX_DATA_TYPE_OCTETSTRING) {
205733598f3aSmartijn 			if (laxi->axi_vb.avb_data.avb_ostring.aos_slen != 0) {
205881180db9Smartijn #ifdef AX_DEBUG
205981180db9Smartijn 				agentx_log_axc_fatalx(axr->axr_axc,
206081180db9Smartijn 				    "%s: implied can only be used on strings "
206181180db9Smartijn 				    "of dynamic length", __func__);
206281180db9Smartijn #else
206381180db9Smartijn 				agentx_log_axc_warnx(axr->axr_axc,
206481180db9Smartijn 				    "%s: implied can only be used on strings "
206581180db9Smartijn 				    "of dynamic length", __func__);
206681180db9Smartijn 				errno = EINVAL;
206781180db9Smartijn 				return NULL;
206881180db9Smartijn #endif
206981180db9Smartijn 			}
207033598f3aSmartijn 		} else if (laxi->axi_vb.avb_type == AX_DATA_TYPE_OID) {
207133598f3aSmartijn 			if (laxi->axi_vb.avb_data.avb_oid.aoi_idlen != 0) {
207281180db9Smartijn #ifdef AX_DEBUG
207381180db9Smartijn 				agentx_log_axc_fatalx(axr->axr_axc,
207481180db9Smartijn 				    "%s: implied can only be used on oids of "
207581180db9Smartijn 				    "dynamic length", __func__);
207681180db9Smartijn #else
207781180db9Smartijn 				agentx_log_axc_warnx(axr->axr_axc,
207881180db9Smartijn 				    "%s: implied can only be used on oids of "
207981180db9Smartijn 				    "dynamic length", __func__);
208081180db9Smartijn 				errno = EINVAL;
208181180db9Smartijn 				return NULL;
208281180db9Smartijn #endif
208381180db9Smartijn 			}
208481180db9Smartijn 		} else {
208581180db9Smartijn #ifdef AX_DEBUG
208681180db9Smartijn 			agentx_log_axc_fatalx(axr->axr_axc, "%s: implied "
208781180db9Smartijn 			    "can only be set on oid and string indices",
208881180db9Smartijn 			    __func__);
208981180db9Smartijn #else
209081180db9Smartijn 			agentx_log_axc_warnx(axr->axr_axc, "%s: implied can "
209181180db9Smartijn 			    "only be set on oid and string indices", __func__);
209281180db9Smartijn 			errno = EINVAL;
209381180db9Smartijn 			return NULL;
209481180db9Smartijn #endif
20959dbe2cd1Smartijn 		}
20969dbe2cd1Smartijn 	}
209781180db9Smartijn 
209881180db9Smartijn 	ready = axr->axr_cstate == AX_CSTATE_OPEN;
209981180db9Smartijn 	if ((axo = calloc(1, sizeof(*axo))) == NULL)
210081180db9Smartijn 		return NULL;
210181180db9Smartijn 	axo->axo_axr = axr;
210281180db9Smartijn 	bcopy(&(axo_search.axo_oid), &(axo->axo_oid), sizeof(axo->axo_oid));
210381180db9Smartijn 	for (i = 0; i < axilen; i++) {
210481180db9Smartijn 		axo->axo_index[i] = axi[i];
210581180db9Smartijn 		if (axi[i]->axi_objectlen == axi[i]->axi_objectsize) {
210633598f3aSmartijn 			taxo = recallocarray(axi[i]->axi_object,
210781180db9Smartijn 			    axi[i]->axi_objectlen, axi[i]->axi_objectlen + 1,
210881180db9Smartijn 			    sizeof(*axi[i]->axi_object));
210933598f3aSmartijn 			if (taxo == NULL) {
211081180db9Smartijn 				free(axo);
211181180db9Smartijn 				return NULL;
211281180db9Smartijn 			}
211333598f3aSmartijn 			axi[i]->axi_object = taxo;
211481180db9Smartijn 			axi[i]->axi_objectsize = axi[i]->axi_objectlen + 1;
211581180db9Smartijn 		}
211681180db9Smartijn 		for (j = 0; j < axi[i]->axi_objectlen; j++) {
211781180db9Smartijn 			if (ax_oid_cmp(&(axo->axo_oid),
211881180db9Smartijn 			    &(axi[i]->axi_object[j]->axo_oid)) < 0) {
211981180db9Smartijn 				memmove(&(axi[i]->axi_object[j + 1]),
212081180db9Smartijn 				    &(axi[i]->axi_object[j]),
212181180db9Smartijn 				    sizeof(*(axi[i]->axi_object)) *
212281180db9Smartijn 				    (axi[i]->axi_objectlen - j));
212381180db9Smartijn 				break;
212481180db9Smartijn 			}
212581180db9Smartijn 		}
212681180db9Smartijn 		axi[i]->axi_object[j] = axo;
212781180db9Smartijn 		axi[i]->axi_objectlen++;
212881180db9Smartijn 		if (axi[i]->axi_cstate != AX_CSTATE_OPEN)
212981180db9Smartijn 			ready = 0;
213081180db9Smartijn 	}
213181180db9Smartijn 	axo->axo_indexlen = axilen;
213281180db9Smartijn 	axo->axo_implied = implied;
213381180db9Smartijn 	axo->axo_timeout = 0;
213481180db9Smartijn 	axo->axo_lock = 0;
213581180db9Smartijn 	axo->axo_get = get;
213681180db9Smartijn 	axo->axo_cstate = AX_CSTATE_CLOSE;
213781180db9Smartijn 	axo->axo_dstate = AX_DSTATE_OPEN;
213881180db9Smartijn 
213981180db9Smartijn 	TAILQ_INSERT_TAIL(&(axr->axr_objects), axo, axo_axr_objects);
214081180db9Smartijn 	RB_INSERT(axc_objects, &(axr->axr_axc->axc_objects), axo);
214181180db9Smartijn 
214281180db9Smartijn 	if (ready)
214381180db9Smartijn 		agentx_object_start(axo);
214481180db9Smartijn 
214581180db9Smartijn 	return axo;
214681180db9Smartijn }
214781180db9Smartijn 
214881180db9Smartijn static int
214981180db9Smartijn agentx_object_start(struct agentx_object *axo)
215081180db9Smartijn {
215181180db9Smartijn 	struct agentx_region *axr = axo->axo_axr;
215281180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
215381180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
215481180db9Smartijn 	struct agentx *ax = axs->axs_ax;
215581180db9Smartijn 	struct ax_oid oid;
215681180db9Smartijn 	char oids[1024];
215781180db9Smartijn 	size_t i;
215881180db9Smartijn 	int needregister = 0;
215981180db9Smartijn 	uint32_t packetid;
216081180db9Smartijn 	uint8_t flags = AX_PDU_FLAG_INSTANCE_REGISTRATION;
216181180db9Smartijn 
216281180db9Smartijn #ifdef AX_DEBUG
216381180db9Smartijn 	if (axr->axr_cstate != AX_CSTATE_OPEN ||
216481180db9Smartijn 	    axo->axo_cstate != AX_CSTATE_CLOSE ||
216581180db9Smartijn 	    axo->axo_dstate != AX_DSTATE_OPEN)
216681180db9Smartijn 		agentx_log_axc_fatalx(axc,
216781180db9Smartijn 		    "%s: unexpected object registration", __func__);
216881180db9Smartijn #endif
216981180db9Smartijn 
217081180db9Smartijn 	if (axo->axo_timeout != 0)
217181180db9Smartijn 		needregister = 1;
217281180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
217381180db9Smartijn 		if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
217481180db9Smartijn 			return 0;
217581180db9Smartijn 		if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
217681180db9Smartijn 			needregister = 1;
217781180db9Smartijn 	}
217881180db9Smartijn 	if (!needregister) {
217981180db9Smartijn 		axo->axo_cstate = AX_CSTATE_WAITOPEN;
218081180db9Smartijn 		agentx_object_finalize(NULL, axo);
21819dbe2cd1Smartijn 		return 0;
21829dbe2cd1Smartijn 	}
21839dbe2cd1Smartijn 
218481180db9Smartijn 	bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
218581180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
218681180db9Smartijn 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
218781180db9Smartijn 			flags = 0;
218881180db9Smartijn 			break;
218981180db9Smartijn 		}
219081180db9Smartijn #ifdef AX_DEBUG
219181180db9Smartijn 		if (axo->axo_index[i]->axi_vb.avb_type !=
219281180db9Smartijn 		    AX_DATA_TYPE_INTEGER)
219381180db9Smartijn 			agentx_log_axc_fatalx(axc,
219481180db9Smartijn 			    "%s: Unsupported allocated index type", __func__);
219581180db9Smartijn #endif
219681180db9Smartijn 		oid.aoi_id[oid.aoi_idlen++] =
21971b6ededeSmartijn 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
219881180db9Smartijn 	}
219981180db9Smartijn 	packetid = ax_register(ax->ax_ax, flags, axs->axs_id,
220081180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), axo->axo_timeout,
220181180db9Smartijn 	    AX_PRIORITY_DEFAULT, 0, &oid, 0);
220281180db9Smartijn 	if (packetid == 0) {
220381180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
220481180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_REGISTER));
220581180db9Smartijn 		agentx_reset(ax);
220681180db9Smartijn 		return -1;
220781180db9Smartijn 	}
220881180db9Smartijn 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
220981180db9Smartijn 	agentx_log_axc_info(axc, "object %s (%s %s): opening",
221081180db9Smartijn 	    oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
221181180db9Smartijn 	axo->axo_cstate = AX_CSTATE_WAITOPEN;
221281180db9Smartijn 	return agentx_request(ax, packetid, agentx_object_finalize, axo);
22139dbe2cd1Smartijn }
22149dbe2cd1Smartijn 
221581180db9Smartijn static int
221681180db9Smartijn agentx_object_finalize(struct ax_pdu *pdu, void *cookie)
22179dbe2cd1Smartijn {
221881180db9Smartijn 	struct agentx_object *axo = cookie;
221981180db9Smartijn 	struct agentx_context *axc = axo->axo_axr->axr_axc;
222081180db9Smartijn 	struct ax_oid oid;
222181180db9Smartijn 	char oids[1024];
222281180db9Smartijn 	size_t i;
222381180db9Smartijn 	uint8_t flags = 1;
22249dbe2cd1Smartijn 
222581180db9Smartijn #ifdef AX_DEBUG
222681180db9Smartijn 	if (axo->axo_cstate != AX_CSTATE_WAITOPEN)
222781180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: not expecting object open",
222881180db9Smartijn 		    __func__);
222981180db9Smartijn #endif
223081180db9Smartijn 
223181180db9Smartijn 	if (pdu == NULL) {
223281180db9Smartijn 		axo->axo_cstate = AX_CSTATE_OPEN;
223381180db9Smartijn 		return 0;
22349dbe2cd1Smartijn 	}
22359dbe2cd1Smartijn 
223681180db9Smartijn 	bcopy(&(axo->axo_oid), &oid, sizeof(oid));
223781180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
223881180db9Smartijn 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
223981180db9Smartijn 			flags = 0;
224081180db9Smartijn 			break;
224181180db9Smartijn 		}
224281180db9Smartijn #ifdef AX_DEBUG
224381180db9Smartijn 		if (axo->axo_index[i]->axi_vb.avb_type !=
224481180db9Smartijn 		    AX_DATA_TYPE_INTEGER)
224581180db9Smartijn 			agentx_log_axc_fatalx(axc,
224681180db9Smartijn 			    "%s: Unsupported allocated index type", __func__);
224781180db9Smartijn #endif
22489dbe2cd1Smartijn 
224981180db9Smartijn 		oid.aoi_id[oid.aoi_idlen++] =
22501b6ededeSmartijn 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
225181180db9Smartijn 	}
225281180db9Smartijn 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
225381180db9Smartijn 
225481180db9Smartijn 	/*
225581180db9Smartijn 	 * We should only be here for table objects with registered indices.
225681180db9Smartijn 	 * If we fail here something is misconfigured and the admin should fix
225781180db9Smartijn 	 * it.
225881180db9Smartijn 	 */
225981180db9Smartijn 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
226081180db9Smartijn 		axo->axo_cstate = AX_CSTATE_CLOSE;
226181180db9Smartijn 		agentx_log_axc_info(axc, "object %s (%s %s): %s",
226281180db9Smartijn 		    oids, flags ? "instance" : "region", ax_oid2string(&oid),
226381180db9Smartijn 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
226481180db9Smartijn 		return 0;
226581180db9Smartijn 	}
226681180db9Smartijn 	axo->axo_cstate = AX_CSTATE_OPEN;
226781180db9Smartijn 	agentx_log_axc_info(axc, "object %s (%s %s): open", oids,
226881180db9Smartijn 	    flags ? "instance" : "region", ax_oid2string(&oid));
226981180db9Smartijn 
227081180db9Smartijn 	if (axo->axo_dstate == AX_DSTATE_CLOSE)
227181180db9Smartijn 		return agentx_object_close(axo);
227281180db9Smartijn 
227381180db9Smartijn 	return 0;
22749dbe2cd1Smartijn }
22759dbe2cd1Smartijn 
227681180db9Smartijn static int
227781180db9Smartijn agentx_object_lock(struct agentx_object *axo)
227881180db9Smartijn {
227981180db9Smartijn 	if (axo->axo_lock == UINT32_MAX) {
228081180db9Smartijn 		agentx_log_axc_warnx(axo->axo_axr->axr_axc,
228181180db9Smartijn 		    "%s: axo_lock == %u", __func__, UINT32_MAX);
228281180db9Smartijn 		return -1;
228381180db9Smartijn 	}
228481180db9Smartijn 	axo->axo_lock++;
228581180db9Smartijn 	return 0;
228681180db9Smartijn }
228781180db9Smartijn 
228881180db9Smartijn static void
228981180db9Smartijn agentx_object_unlock(struct agentx_object *axo)
229081180db9Smartijn {
2291f00a771dSmartijn 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2292f00a771dSmartijn 
229381180db9Smartijn #ifdef AX_DEBUG
229481180db9Smartijn 	if (axo->axo_lock == 0)
229581180db9Smartijn 		agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
229681180db9Smartijn 		    "%s: axo_lock == 0", __func__);
229781180db9Smartijn #endif
229881180db9Smartijn 	axo->axo_lock--;
2299f00a771dSmartijn 	if (axo->axo_lock == 0) {
2300f00a771dSmartijn 		if (!ax->ax_free)
2301f00a771dSmartijn 			agentx_free_finalize(ax);
2302f00a771dSmartijn 	}
230381180db9Smartijn }
230481180db9Smartijn 
230581180db9Smartijn static int
230681180db9Smartijn agentx_object_close(struct agentx_object *axo)
230781180db9Smartijn {
230881180db9Smartijn 	struct agentx_context *axc = axo->axo_axr->axr_axc;
230981180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
231081180db9Smartijn 	struct agentx *ax = axs->axs_ax;
231181180db9Smartijn 	struct ax_oid oid;
231281180db9Smartijn 	char oids[1024];
231381180db9Smartijn 	size_t i;
231481180db9Smartijn 	int needclose = 0;
231581180db9Smartijn 	uint32_t packetid;
231681180db9Smartijn 	uint8_t flags = 1;
231781180db9Smartijn 
231881180db9Smartijn #ifdef AX_DEBUG
231981180db9Smartijn 	if (axo->axo_cstate != AX_CSTATE_OPEN)
232081180db9Smartijn 		agentx_log_axc_fatalx(axc, "%s: unexpected object close",
232181180db9Smartijn 		    __func__);
232281180db9Smartijn #endif
232381180db9Smartijn 
232481180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
232581180db9Smartijn #ifdef AX_DEBUG
232681180db9Smartijn 		if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
232781180db9Smartijn 			agentx_log_axc_fatalx(axc,
232881180db9Smartijn 			    "%s: Object open while index closed", __func__);
232981180db9Smartijn #endif
233081180db9Smartijn 		if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
233181180db9Smartijn 			needclose = 1;
233281180db9Smartijn 	}
233381180db9Smartijn 	axo->axo_cstate = AX_CSTATE_WAITCLOSE;
233481180db9Smartijn 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
233581180db9Smartijn 		return 0;
233681180db9Smartijn 	if (!needclose) {
233781180db9Smartijn 		agentx_object_close_finalize(NULL, axo);
233881180db9Smartijn 		return 0;
233981180db9Smartijn 	}
234081180db9Smartijn 
234181180db9Smartijn 	bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
234281180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
234381180db9Smartijn 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
234481180db9Smartijn 			flags = 0;
234581180db9Smartijn 			break;
234681180db9Smartijn 		}
234781180db9Smartijn #ifdef AX_DEBUG
234881180db9Smartijn 		if (axo->axo_index[i]->axi_vb.avb_type !=
234981180db9Smartijn 		    AX_DATA_TYPE_INTEGER)
235081180db9Smartijn 			agentx_log_axc_fatalx(axc,
235181180db9Smartijn 			    "%s: Unsupported allocated index type", __func__);
235281180db9Smartijn #endif
235381180db9Smartijn 		oid.aoi_id[oid.aoi_idlen++] =
23541b6ededeSmartijn 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
235581180db9Smartijn 	}
235681180db9Smartijn 	packetid = ax_unregister(ax->ax_ax, axs->axs_id,
235781180db9Smartijn 	    AGENTX_CONTEXT_CTX(axc), AX_PRIORITY_DEFAULT, 0, &oid, 0);
235881180db9Smartijn 	if (packetid == 0) {
235981180db9Smartijn 		agentx_log_axc_warn(axc, "couldn't generate %s",
236081180db9Smartijn 		    ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
236181180db9Smartijn 		agentx_reset(ax);
236281180db9Smartijn 		return -1;
236381180db9Smartijn 	}
236481180db9Smartijn 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
236581180db9Smartijn 	agentx_log_axc_info(axc, "object %s (%s %s): closing",
236681180db9Smartijn 	    oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
236781180db9Smartijn 	return agentx_request(ax, packetid, agentx_object_close_finalize,
236881180db9Smartijn 	    axo);
236981180db9Smartijn }
237081180db9Smartijn 
237181180db9Smartijn static int
237281180db9Smartijn agentx_object_close_finalize(struct ax_pdu *pdu, void *cookie)
237381180db9Smartijn {
237481180db9Smartijn 	struct agentx_object *axo = cookie;
237581180db9Smartijn 	struct agentx_region *axr = axo->axo_axr;
237681180db9Smartijn 	struct agentx_context *axc = axr->axr_axc;
237781180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
237881180db9Smartijn 	struct agentx *ax = axs->axs_ax;
237981180db9Smartijn 	struct ax_oid oid;
238081180db9Smartijn 	char oids[1024];
238181180db9Smartijn 	uint8_t flags = 1;
238281180db9Smartijn 	size_t i;
2383f00a771dSmartijn 	int axfree = ax->ax_free;
238481180db9Smartijn 
238581180db9Smartijn #ifdef AX_DEBUG
238681180db9Smartijn 	if (axo->axo_cstate != AX_CSTATE_WAITCLOSE)
238781180db9Smartijn 		agentx_log_axc_fatalx(axc,
238881180db9Smartijn 		    "%s: unexpected object unregister", __func__);
238981180db9Smartijn #endif
239081180db9Smartijn 
239181180db9Smartijn 	if (pdu != NULL) {
239281180db9Smartijn 		bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
239381180db9Smartijn 		for (i = 0; i < axo->axo_indexlen; i++) {
239481180db9Smartijn 			if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
239581180db9Smartijn 				flags = 0;
239681180db9Smartijn 				break;
239781180db9Smartijn 			}
239881180db9Smartijn #ifdef AX_DEBUG
239981180db9Smartijn 			if (axo->axo_index[i]->axi_vb.avb_type !=
240081180db9Smartijn 			    AX_DATA_TYPE_INTEGER)
240181180db9Smartijn 				agentx_log_axc_fatalx(axc,
240281180db9Smartijn 				    "%s: Unsupported allocated index type",
240381180db9Smartijn 				    __func__);
240481180db9Smartijn #endif
240581180db9Smartijn 			oid.aoi_id[oid.aoi_idlen++] =
24061b6ededeSmartijn 			    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
240781180db9Smartijn 		}
240881180db9Smartijn 		strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
240981180db9Smartijn 		if (pdu->ap_payload.ap_response.ap_error !=
241081180db9Smartijn 		    AX_PDU_ERROR_NOERROR) {
241181180db9Smartijn 			agentx_log_axc_warnx(axc,
241281180db9Smartijn 			    "closing object %s (%s %s): %s", oids,
241381180db9Smartijn 			    flags ? "instance" : "region",
241481180db9Smartijn 			    ax_oid2string(&oid), ax_error2string(
241581180db9Smartijn 			    pdu->ap_payload.ap_response.ap_error));
241681180db9Smartijn 			agentx_reset(ax);
241781180db9Smartijn 			return -1;
241881180db9Smartijn 		}
241981180db9Smartijn 		agentx_log_axc_info(axc, "object %s (%s %s): closed", oids,
242081180db9Smartijn 		    flags ? "instance" : "region", ax_oid2string(&oid));
242181180db9Smartijn 	}
242281180db9Smartijn 
2423f00a771dSmartijn 	ax->ax_free = 1;
2424f00a771dSmartijn 	if (axr->axr_cstate == AX_CSTATE_OPEN &&
2425f00a771dSmartijn 	    axo->axo_dstate == AX_DSTATE_OPEN)
2426f00a771dSmartijn 		agentx_object_start(axo);
2427f00a771dSmartijn 
2428f00a771dSmartijn 	if (!axfree)
2429f00a771dSmartijn 		agentx_free_finalize(ax);
243081180db9Smartijn 
243181180db9Smartijn 	return 0;
243281180db9Smartijn }
243381180db9Smartijn 
243481180db9Smartijn void
243581180db9Smartijn agentx_object_free(struct agentx_object *axo)
243681180db9Smartijn {
2437f00a771dSmartijn 	struct agentx *ax;
2438f00a771dSmartijn 	int axfree;
2439f00a771dSmartijn 
244081180db9Smartijn 	if (axo == NULL)
244181180db9Smartijn 		return;
244281180db9Smartijn 
2443f00a771dSmartijn 	ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2444f00a771dSmartijn 	axfree = ax->ax_free;
2445f00a771dSmartijn 	ax->ax_free = 1;
2446f00a771dSmartijn 
244781180db9Smartijn 	if (axo->axo_dstate == AX_DSTATE_CLOSE)
244881180db9Smartijn 		agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
244981180db9Smartijn 		    "%s: double free", __func__);
245081180db9Smartijn 
245181180db9Smartijn 	axo->axo_dstate = AX_DSTATE_CLOSE;
245281180db9Smartijn 
2453f00a771dSmartijn 	if (axo->axo_cstate == AX_CSTATE_OPEN)
2454f00a771dSmartijn 		agentx_object_close(axo);
2455f00a771dSmartijn 	if (!axfree)
2456f00a771dSmartijn 		agentx_free_finalize(ax);
245781180db9Smartijn }
245881180db9Smartijn 
245981180db9Smartijn static void
246081180db9Smartijn agentx_object_free_finalize(struct agentx_object *axo)
246181180db9Smartijn {
246281180db9Smartijn #ifdef AX_DEBUG
246381180db9Smartijn 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
246481180db9Smartijn #endif
246581180db9Smartijn 	size_t i, j;
246681180db9Smartijn 	int found;
246781180db9Smartijn 
2468f00a771dSmartijn 	if (axo->axo_dstate != AX_DSTATE_CLOSE ||
2469f00a771dSmartijn 	    axo->axo_cstate != AX_CSTATE_CLOSE ||
2470f00a771dSmartijn 	    axo->axo_lock != 0)
247181180db9Smartijn 		return;
247281180db9Smartijn 
247381180db9Smartijn 	RB_REMOVE(axc_objects, &(axo->axo_axr->axr_axc->axc_objects), axo);
247481180db9Smartijn 	TAILQ_REMOVE(&(axo->axo_axr->axr_objects), axo, axo_axr_objects);
247581180db9Smartijn 
247681180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
247781180db9Smartijn 		found = 0;
247881180db9Smartijn 		for (j = 0; j < axo->axo_index[i]->axi_objectlen; j++) {
247981180db9Smartijn 			if (axo->axo_index[i]->axi_object[j] == axo)
248081180db9Smartijn 				found = 1;
248181180db9Smartijn 			if (found && j + 1 != axo->axo_index[i]->axi_objectlen)
248281180db9Smartijn 				axo->axo_index[i]->axi_object[j] =
248381180db9Smartijn 				    axo->axo_index[i]->axi_object[j + 1];
248481180db9Smartijn 		}
248581180db9Smartijn #ifdef AX_DEBUG
248681180db9Smartijn 		if (!found)
248781180db9Smartijn 			agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
248881180db9Smartijn 			    "%s: object not found in index", __func__);
248981180db9Smartijn #endif
249081180db9Smartijn 		axo->axo_index[i]->axi_objectlen--;
249181180db9Smartijn 	}
249281180db9Smartijn 
249381180db9Smartijn 	free(axo);
249481180db9Smartijn }
249581180db9Smartijn 
249681180db9Smartijn static void
249781180db9Smartijn agentx_object_reset(struct agentx_object *axo)
249881180db9Smartijn {
2499f00a771dSmartijn 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2500f00a771dSmartijn 
250181180db9Smartijn 	axo->axo_cstate = AX_CSTATE_CLOSE;
250281180db9Smartijn 
2503f00a771dSmartijn 	if (!ax->ax_free)
2504f00a771dSmartijn 		agentx_free_finalize(ax);
250581180db9Smartijn }
250681180db9Smartijn 
250781180db9Smartijn static int
250881180db9Smartijn agentx_object_cmp(struct agentx_object *o1, struct agentx_object *o2)
250981180db9Smartijn {
251081180db9Smartijn 	return ax_oid_cmp(&(o1->axo_oid), &(o2->axo_oid));
251181180db9Smartijn }
251281180db9Smartijn 
251381180db9Smartijn static int
251481180db9Smartijn agentx_object_implied(struct agentx_object *axo,
251581180db9Smartijn     struct agentx_index *axi)
25169dbe2cd1Smartijn {
25179dbe2cd1Smartijn 	size_t i = 0;
2518af021b53Smartijn 	struct ax_varbind *vb;
25199dbe2cd1Smartijn 
252081180db9Smartijn 	for (i = 0; i < axo->axo_indexlen; i++) {
252181180db9Smartijn 		if (axo->axo_index[i] == axi) {
2522af021b53Smartijn 			vb = &axi->axi_vb;
2523af021b53Smartijn 			if (vb->avb_type == AX_DATA_TYPE_OCTETSTRING &&
2524af021b53Smartijn 			    vb->avb_data.avb_ostring.aos_slen != 0)
2525af021b53Smartijn 				return 1;
2526af021b53Smartijn 			else if (vb->avb_type == AX_DATA_TYPE_OID &&
2527af021b53Smartijn 			    vb->avb_data.avb_oid.aoi_idlen != 0)
252881180db9Smartijn 				return 1;
252981180db9Smartijn 			else if (i == axo->axo_indexlen - 1)
253081180db9Smartijn 				return axo->axo_implied;
25319dbe2cd1Smartijn 			return 0;
25329dbe2cd1Smartijn 		}
253381180db9Smartijn 	}
253481180db9Smartijn #ifdef AX_DEBUG
253581180db9Smartijn 	agentx_log_axc_fatalx(axo->axo_axr->axr_axc, "%s: unsupported index",
253681180db9Smartijn 	    __func__);
253781180db9Smartijn #endif
253881180db9Smartijn 	return 0;
253981180db9Smartijn }
254081180db9Smartijn 
254181180db9Smartijn static void
254281180db9Smartijn agentx_get_start(struct agentx_context *axc, struct ax_pdu *pdu)
254381180db9Smartijn {
254481180db9Smartijn 	struct agentx_session *axs = axc->axc_axs;
254581180db9Smartijn 	struct agentx *ax = axs->axs_ax;
254633598f3aSmartijn 	struct agentx_get *axg, taxg;
254781180db9Smartijn 	struct ax_pdu_searchrangelist *srl;
254881180db9Smartijn 	char *logmsg = NULL;
254981180db9Smartijn 	size_t i, j;
255081180db9Smartijn 	int fail = 0;
255181180db9Smartijn 
255281180db9Smartijn 	if ((axg = calloc(1, sizeof(*axg))) == NULL) {
255333598f3aSmartijn 		taxg.axg_sessionid = pdu->ap_header.aph_sessionid;
255433598f3aSmartijn 		taxg.axg_transactionid = pdu->ap_header.aph_transactionid;
255533598f3aSmartijn 		taxg.axg_packetid = pdu->ap_header.aph_packetid;
255633598f3aSmartijn 		taxg.axg_context_default = axc->axc_name_default;
255733598f3aSmartijn 		taxg.axg_fd = axc->axc_axs->axs_ax->ax_fd;
255833598f3aSmartijn 		agentx_log_axg_warn(&taxg, "Couldn't parse request");
255981180db9Smartijn 		agentx_reset(ax);
256081180db9Smartijn 		return;
256181180db9Smartijn 	}
256281180db9Smartijn 
256381180db9Smartijn 	axg->axg_sessionid = pdu->ap_header.aph_sessionid;
256481180db9Smartijn 	axg->axg_transactionid = pdu->ap_header.aph_transactionid;
256581180db9Smartijn 	axg->axg_packetid = pdu->ap_header.aph_packetid;
256681180db9Smartijn 	axg->axg_context_default = axc->axc_name_default;
256781180db9Smartijn 	axg->axg_fd = axc->axc_axs->axs_ax->ax_fd;
256881180db9Smartijn 	if (!axc->axc_name_default) {
256981180db9Smartijn 		axg->axg_context.aos_string =
257081180db9Smartijn 		    (unsigned char *)strdup((char *)axc->axc_name.aos_string);
257181180db9Smartijn 		if (axg->axg_context.aos_string == NULL) {
257281180db9Smartijn 			agentx_log_axg_warn(axg, "Couldn't parse request");
257381180db9Smartijn 			free(axg);
257481180db9Smartijn 			agentx_reset(ax);
257581180db9Smartijn 			return;
257681180db9Smartijn 		}
257781180db9Smartijn 	}
257881180db9Smartijn 	axg->axg_context.aos_slen = axc->axc_name.aos_slen;
257981180db9Smartijn 	axg->axg_type = pdu->ap_header.aph_type;
258081180db9Smartijn 	axg->axg_axc = axc;
258181180db9Smartijn 	TAILQ_INSERT_TAIL(&(ax->ax_getreqs), axg, axg_ax_getreqs);
258281180db9Smartijn 	if (axg->axg_type == AX_PDU_TYPE_GET ||
258381180db9Smartijn 	    axg->axg_type == AX_PDU_TYPE_GETNEXT) {
258481180db9Smartijn 		srl = &(pdu->ap_payload.ap_srl);
258581180db9Smartijn 		axg->axg_nvarbind = srl->ap_nsr;
258681180db9Smartijn 	} else {
258781180db9Smartijn 		axg->axg_nonrep = pdu->ap_payload.ap_getbulk.ap_nonrep;
258881180db9Smartijn 		axg->axg_maxrep = pdu->ap_payload.ap_getbulk.ap_maxrep;
258981180db9Smartijn 		srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
259081180db9Smartijn 		axg->axg_nvarbind = ((srl->ap_nsr - axg->axg_nonrep) *
259181180db9Smartijn 		    axg->axg_maxrep) + axg->axg_nonrep;
259281180db9Smartijn 	}
259381180db9Smartijn 
259481180db9Smartijn 	if ((axg->axg_varbind = calloc(axg->axg_nvarbind,
259581180db9Smartijn 	    sizeof(*(axg->axg_varbind)))) == NULL) {
259681180db9Smartijn 		agentx_log_axg_warn(axg, "Couldn't parse request");
259781180db9Smartijn 		agentx_get_free(axg);
259881180db9Smartijn 		agentx_reset(ax);
259981180db9Smartijn 		return;
260081180db9Smartijn 	}
260181180db9Smartijn 
260281180db9Smartijn 	/* XXX net-snmp doesn't use getbulk, so untested */
260381180db9Smartijn 	/* Two loops: varbind after needs to be initialized */
260481180db9Smartijn 	for (i = 0; i < srl->ap_nsr; i++) {
260581180db9Smartijn 		if (i < axg->axg_nonrep ||
260681180db9Smartijn 		    axg->axg_type != AX_PDU_TYPE_GETBULK)
260781180db9Smartijn 			j = i;
260881180db9Smartijn 		else if (axg->axg_maxrep == 0)
260981180db9Smartijn 			break;
261081180db9Smartijn 		else
261181180db9Smartijn 			j = (axg->axg_maxrep * i) + axg->axg_nonrep;
261281180db9Smartijn 		bcopy(&(srl->ap_sr[i].asr_start),
261381180db9Smartijn 		    &(axg->axg_varbind[j].axv_vb.avb_oid),
261481180db9Smartijn 		    sizeof(srl->ap_sr[i].asr_start));
261581180db9Smartijn 		bcopy(&(srl->ap_sr[i].asr_start),
261681180db9Smartijn 		    &(axg->axg_varbind[j].axv_start),
261781180db9Smartijn 		    sizeof(srl->ap_sr[i].asr_start));
261881180db9Smartijn 		bcopy(&(srl->ap_sr[i].asr_stop),
261981180db9Smartijn 		    &(axg->axg_varbind[j].axv_end),
262081180db9Smartijn 		    sizeof(srl->ap_sr[i].asr_stop));
262181180db9Smartijn 		axg->axg_varbind[j].axv_initialized = 1;
262281180db9Smartijn 		axg->axg_varbind[j].axv_axg = axg;
262381180db9Smartijn 		axg->axg_varbind[j].axv_include =
262481180db9Smartijn 		    srl->ap_sr[i].asr_start.aoi_include;
262581180db9Smartijn 		if (j == 0)
262681180db9Smartijn 			fail |= agentx_strcat(&logmsg, " {");
262781180db9Smartijn 		else
262881180db9Smartijn 			fail |= agentx_strcat(&logmsg, ",{");
262981180db9Smartijn 		fail |= agentx_strcat(&logmsg,
263081180db9Smartijn 		    ax_oid2string(&(srl->ap_sr[i].asr_start)));
263181180db9Smartijn 		if (srl->ap_sr[i].asr_start.aoi_include)
263281180db9Smartijn 			fail |= agentx_strcat(&logmsg, " (inclusive)");
263381180db9Smartijn 		if (srl->ap_sr[i].asr_stop.aoi_idlen != 0) {
263481180db9Smartijn 			fail |= agentx_strcat(&logmsg, " - ");
263581180db9Smartijn 			fail |= agentx_strcat(&logmsg,
263681180db9Smartijn 			    ax_oid2string(&(srl->ap_sr[i].asr_stop)));
263781180db9Smartijn 		}
263881180db9Smartijn 		fail |= agentx_strcat(&logmsg, "}");
263981180db9Smartijn 		if (fail) {
264081180db9Smartijn 			agentx_log_axg_warn(axg, "Couldn't parse request");
264181180db9Smartijn 			free(logmsg);
264281180db9Smartijn 			agentx_get_free(axg);
264381180db9Smartijn 			agentx_reset(ax);
264481180db9Smartijn 			return;
264581180db9Smartijn 		}
264681180db9Smartijn 	}
264781180db9Smartijn 
264881180db9Smartijn 	agentx_log_axg_debug(axg, "%s:%s",
264981180db9Smartijn 	    ax_pdutype2string(axg->axg_type), logmsg);
265081180db9Smartijn 	free(logmsg);
265181180db9Smartijn 
265281180db9Smartijn 	for (i = 0; i < srl->ap_nsr; i++) {
265381180db9Smartijn 		if (i < axg->axg_nonrep ||
265481180db9Smartijn 		    axg->axg_type != AX_PDU_TYPE_GETBULK)
265581180db9Smartijn 			j = i;
265681180db9Smartijn 		else if (axg->axg_maxrep == 0)
265781180db9Smartijn 			break;
265881180db9Smartijn 		else
265981180db9Smartijn 			j = (axg->axg_maxrep * i) + axg->axg_nonrep;
266081180db9Smartijn 		agentx_varbind_start(&(axg->axg_varbind[j]));
266181180db9Smartijn 	}
266281180db9Smartijn }
266381180db9Smartijn 
266481180db9Smartijn static void
266581180db9Smartijn agentx_get_finalize(struct agentx_get *axg)
266681180db9Smartijn {
266781180db9Smartijn 	struct agentx_context *axc = axg->axg_axc;
266856d20486Smartijn 	struct agentx_session *axs;
266956d20486Smartijn 	struct agentx *ax;
267081180db9Smartijn 	size_t i, j, nvarbind = 0;
267181180db9Smartijn 	uint16_t error = 0, index = 0;
267281180db9Smartijn 	struct ax_varbind *vbl;
267381180db9Smartijn 	char *logmsg = NULL;
267481180db9Smartijn 	int fail = 0;
267581180db9Smartijn 
267681180db9Smartijn 	for (i = 0; i < axg->axg_nvarbind; i++) {
267781180db9Smartijn 		if (axg->axg_varbind[i].axv_initialized) {
267881180db9Smartijn 			if (axg->axg_varbind[i].axv_vb.avb_type == 0)
267981180db9Smartijn 				return;
268081180db9Smartijn 			nvarbind++;
268181180db9Smartijn 		}
268281180db9Smartijn 	}
268381180db9Smartijn 
268456d20486Smartijn 	if (axc == NULL) {
268581180db9Smartijn 		agentx_get_free(axg);
268681180db9Smartijn 		return;
268781180db9Smartijn 	}
268881180db9Smartijn 
268956d20486Smartijn 	axs = axc->axc_axs;
269056d20486Smartijn 	ax = axs->axs_ax;
269156d20486Smartijn 
269281180db9Smartijn 	if ((vbl = calloc(nvarbind, sizeof(*vbl))) == NULL) {
269381180db9Smartijn 		agentx_log_axg_warn(axg, "Couldn't parse request");
269481180db9Smartijn 		agentx_get_free(axg);
269581180db9Smartijn 		agentx_reset(ax);
269681180db9Smartijn 		return;
269781180db9Smartijn 	}
269881180db9Smartijn 	for (i = 0, j = 0; i < axg->axg_nvarbind; i++) {
269981180db9Smartijn 		if (axg->axg_varbind[i].axv_initialized) {
270081180db9Smartijn 			memcpy(&(vbl[j]), &(axg->axg_varbind[i].axv_vb),
270181180db9Smartijn 			    sizeof(*vbl));
270281180db9Smartijn 			if (error == 0 && axg->axg_varbind[i].axv_error !=
270381180db9Smartijn 			    AX_PDU_ERROR_NOERROR) {
270481180db9Smartijn 				error = axg->axg_varbind[i].axv_error;
270581180db9Smartijn 				index = j + 1;
270681180db9Smartijn 			}
270781180db9Smartijn 			if (j == 0)
270881180db9Smartijn 				fail |= agentx_strcat(&logmsg, " {");
270981180db9Smartijn 			else
271081180db9Smartijn 				fail |= agentx_strcat(&logmsg, ",{");
271181180db9Smartijn 			fail |= agentx_strcat(&logmsg,
271281180db9Smartijn 			    ax_varbind2string(&(vbl[j])));
271381180db9Smartijn 			if (axg->axg_varbind[i].axv_error !=
271481180db9Smartijn 			    AX_PDU_ERROR_NOERROR) {
271581180db9Smartijn 				fail |= agentx_strcat(&logmsg, "(");
271681180db9Smartijn 				fail |= agentx_strcat(&logmsg,
271781180db9Smartijn 				    ax_error2string(
271881180db9Smartijn 				    axg->axg_varbind[i].axv_error));
271981180db9Smartijn 				fail |= agentx_strcat(&logmsg, ")");
272081180db9Smartijn 			}
272181180db9Smartijn 			fail |= agentx_strcat(&logmsg, "}");
272281180db9Smartijn 			if (fail) {
272381180db9Smartijn 				agentx_log_axg_warn(axg,
272481180db9Smartijn 				    "Couldn't parse request");
272581180db9Smartijn 				free(logmsg);
272681180db9Smartijn 				agentx_get_free(axg);
272781180db9Smartijn 				return;
272881180db9Smartijn 			}
272981180db9Smartijn 			j++;
273081180db9Smartijn 		}
273181180db9Smartijn 	}
273281180db9Smartijn 	agentx_log_axg_debug(axg, "response:%s", logmsg);
273381180db9Smartijn 	free(logmsg);
273481180db9Smartijn 
273581180db9Smartijn 	if (ax_response(ax->ax_ax, axs->axs_id, axg->axg_transactionid,
27366f5d9364Smartijn 	    axg->axg_packetid, 0, error, index, vbl, nvarbind) == -1) {
273781180db9Smartijn 		agentx_log_axg_warn(axg, "Couldn't parse request");
273881180db9Smartijn 		agentx_reset(ax);
273981180db9Smartijn 	} else
274081180db9Smartijn 		agentx_wantwrite(ax, ax->ax_fd);
274181180db9Smartijn 	free(vbl);
274281180db9Smartijn 	agentx_get_free(axg);
274381180db9Smartijn }
274481180db9Smartijn 
274581180db9Smartijn void
274681180db9Smartijn agentx_get_free(struct agentx_get *axg)
274781180db9Smartijn {
274881180db9Smartijn 	struct agentx_varbind *axv;
274981180db9Smartijn 	struct agentx_object *axo;
275056d20486Smartijn 	struct agentx *ax;
275181180db9Smartijn 	struct agentx_varbind_index *index;
275281180db9Smartijn 	size_t i, j;
275381180db9Smartijn 
275456d20486Smartijn 	if (axg->axg_axc != NULL) {
275556d20486Smartijn 		ax = axg->axg_axc->axc_axs->axs_ax;
275681180db9Smartijn 		TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
275756d20486Smartijn 	}
275881180db9Smartijn 
275981180db9Smartijn 	for (i = 0; i < axg->axg_nvarbind; i++) {
276081180db9Smartijn 		axv = &(axg->axg_varbind[i]);
276181180db9Smartijn 		for (j = 0; axv->axv_axo != NULL &&
276281180db9Smartijn 		    j < axv->axv_axo->axo_indexlen; j++) {
276381180db9Smartijn 			axo = axv->axv_axo;
276481180db9Smartijn 			index = &(axv->axv_index[j]);
276581180db9Smartijn 			if (axo->axo_index[j]->axi_vb.avb_type ==
276681180db9Smartijn 			    AX_DATA_TYPE_OCTETSTRING ||
276781180db9Smartijn 			    axo->axo_index[j]->axi_vb.avb_type ==
276881180db9Smartijn 			    AX_DATA_TYPE_IPADDRESS)
276981180db9Smartijn 				free(index->axv_idata.avb_ostring.aos_string);
277081180db9Smartijn 		}
277181180db9Smartijn 		ax_varbind_free(&(axg->axg_varbind[i].axv_vb));
277281180db9Smartijn 	}
277381180db9Smartijn 
277481180db9Smartijn 	free(axg->axg_context.aos_string);
277581180db9Smartijn 	free(axg->axg_varbind);
277681180db9Smartijn 	free(axg);
277781180db9Smartijn }
277881180db9Smartijn 
277981180db9Smartijn static void
278081180db9Smartijn agentx_varbind_start(struct agentx_varbind *axv)
278181180db9Smartijn {
278281180db9Smartijn 	struct agentx_get *axg = axv->axv_axg;
278381180db9Smartijn 	struct agentx_context *axc = axg->axg_axc;
278481180db9Smartijn 	struct agentx_object *axo, axo_search;
278581180db9Smartijn 	struct agentx_varbind_index *index;
278681180db9Smartijn 	struct ax_oid *oid;
278781180db9Smartijn 	union ax_data *data;
278881180db9Smartijn 	struct in_addr *ipaddress;
278981180db9Smartijn 	unsigned char *ipbytes;
279081180db9Smartijn 	size_t i, j, k;
279181180db9Smartijn 	int overflow = 0, dynamic;
279281180db9Smartijn 
279381180db9Smartijn #ifdef AX_DEBUG
279481180db9Smartijn 	if (!axv->axv_initialized)
279581180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg,
279681180db9Smartijn 		    "%s: axv_initialized not set", __func__);
279781180db9Smartijn #endif
279881180db9Smartijn 
279956d20486Smartijn 	if (axc == NULL) {
280056d20486Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
280156d20486Smartijn 		return;
280256d20486Smartijn 	}
280356d20486Smartijn 
280481180db9Smartijn 	bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
280581180db9Smartijn 	    sizeof(axo_search.axo_oid));
280681180db9Smartijn 
280781180db9Smartijn 	do {
280881180db9Smartijn 		axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
280981180db9Smartijn 		if (axo_search.axo_oid.aoi_idlen > 0)
281081180db9Smartijn 			axo_search.axo_oid.aoi_idlen--;
281181180db9Smartijn 	} while (axo == NULL && axo_search.axo_oid.aoi_idlen > 0);
281281180db9Smartijn 	if (axo == NULL || axo->axo_cstate != AX_CSTATE_OPEN) {
281381180db9Smartijn 		axv->axv_include = 1;
281481180db9Smartijn 		if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
281581180db9Smartijn 			agentx_varbind_nosuchobject(axv);
281681180db9Smartijn 			return;
281781180db9Smartijn 		}
281881180db9Smartijn 		bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
281981180db9Smartijn 		    sizeof(axo_search.axo_oid));
282081180db9Smartijn 		axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
282181180db9Smartijn getnext:
282281180db9Smartijn 		while (axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
282381180db9Smartijn 			axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
2824fd375ddbSmartijn 		if (axo == NULL ||
2825*c5fcbd5aSmartijn 		    ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) >= 0) {
282681180db9Smartijn 			agentx_varbind_endofmibview(axv);
282781180db9Smartijn 			return;
282881180db9Smartijn 		}
282981180db9Smartijn 		bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
283081180db9Smartijn 		    sizeof(axo->axo_oid));
283181180db9Smartijn 	}
283281180db9Smartijn 	axv->axv_axo = axo;
283381180db9Smartijn 	axv->axv_indexlen = axo->axo_indexlen;
283481180db9Smartijn 	if (agentx_object_lock(axo) == -1) {
283581180db9Smartijn 		agentx_varbind_error_type(axv,
283681180db9Smartijn 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
283781180db9Smartijn 		return;
283881180db9Smartijn 	}
283981180db9Smartijn 
284081180db9Smartijn 	oid = &(axv->axv_vb.avb_oid);
284181180db9Smartijn 	if (axo->axo_indexlen == 0) {
284281180db9Smartijn 		if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
284381180db9Smartijn 			if (oid->aoi_idlen != axo->axo_oid.aoi_idlen + 1 ||
284481180db9Smartijn 			    oid->aoi_id[oid->aoi_idlen - 1] != 0) {
284581180db9Smartijn 				agentx_varbind_nosuchinstance(axv);
284681180db9Smartijn 				return;
284781180db9Smartijn 			}
284881180db9Smartijn 		} else {
284981180db9Smartijn 			if (oid->aoi_idlen == axo->axo_oid.aoi_idlen) {
285081180db9Smartijn 				oid->aoi_id[oid->aoi_idlen++] = 0;
285181180db9Smartijn 				axv->axv_include = 1;
285281180db9Smartijn 			} else {
285381180db9Smartijn 				axv->axv_axo = NULL;
285481180db9Smartijn 				agentx_object_unlock(axo);
285581180db9Smartijn 				axo = RB_NEXT(axc_objects, &(axc->axc_objects),
285681180db9Smartijn 				    axo);
285781180db9Smartijn 				goto getnext;
285881180db9Smartijn 			}
285981180db9Smartijn 		}
28600f9df26dSmartijn 		j = oid->aoi_idlen;
28610f9df26dSmartijn 	} else
286281180db9Smartijn 		j = axo->axo_oid.aoi_idlen;
286381180db9Smartijn /*
286481180db9Smartijn  * We can't trust what the client gives us, so sometimes we need to map it to
286581180db9Smartijn  * index type.
286681180db9Smartijn  * - AX_PDU_TYPE_GET: we always return AX_DATA_TYPE_NOSUCHINSTANCE
286781180db9Smartijn  * - AX_PDU_TYPE_GETNEXT:
28680f9df26dSmartijn  *   - Missing OID digits to match indices or !dynamic indices
28692c53affbSjmc  *     (AX_DATA_TYPE_INTEGER) underflows will result in the following indices to
28700f9df26dSmartijn  *     be NUL-initialized and the request type will be set to
287181180db9Smartijn  *     AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
287281180db9Smartijn  *   - An overflow can happen on AX_DATA_TYPE_OCTETSTRING and
28730f9df26dSmartijn  *     AX_DATA_TYPE_IPADDRESS data, and AX_DATA_TYPE_OCTETSTRING and
28740f9df26dSmartijn  *     AX_DATA_TYPE_OID length. This results in request type being set to
287581180db9Smartijn  *     AGENTX_REQUEST_TYPE_GETNEXT and will set the index to its maximum
287681180db9Smartijn  *     value:
287781180db9Smartijn  *     - AX_DATA_TYPE_INTEGER: UINT32_MAX
287881180db9Smartijn  *     - AX_DATA_TYPE_OCTETSTRING: aos_slen = UINT32_MAX and
287981180db9Smartijn  *       aos_string = NULL
288081180db9Smartijn  *     - AX_DATA_TYPE_OID: aoi_idlen = UINT32_MAX and aoi_id[x] = UINT32_MAX
288181180db9Smartijn  *     - AX_DATA_TYPE_IPADDRESS: 255.255.255.255
288281180db9Smartijn  */
28830f9df26dSmartijn 	for (dynamic = 0, i = 0; i < axo->axo_indexlen; i++, j++) {
288481180db9Smartijn 		index = &(axv->axv_index[i]);
288581180db9Smartijn 		index->axv_axi = axo->axo_index[i];
288681180db9Smartijn 		data = &(index->axv_idata);
288781180db9Smartijn 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC)
288881180db9Smartijn 			dynamic = 1;
288981180db9Smartijn 		switch (axo->axo_index[i]->axi_vb.avb_type) {
289081180db9Smartijn 		case AX_DATA_TYPE_INTEGER:
28910f9df26dSmartijn 			if (index->axv_axi->axi_type != AXI_TYPE_DYNAMIC) {
28920f9df26dSmartijn 				index->axv_idata.avb_int32 =
28930f9df26dSmartijn 				    index->axv_axi->axi_vb.avb_data.avb_int32;
28940f9df26dSmartijn 				if (overflow == 0) {
28950f9df26dSmartijn 					if ((uint32_t)index->axv_idata.avb_int32 >
28960f9df26dSmartijn 					    oid->aoi_id[j])
28970f9df26dSmartijn 						overflow = -1;
28980f9df26dSmartijn 					else if ((uint32_t)index->axv_idata.avb_int32 <
28990f9df26dSmartijn 					    oid->aoi_id[j])
29001b6ededeSmartijn 						overflow = 1;
290181180db9Smartijn 				}
29020f9df26dSmartijn 			} else if (overflow == 1)
29030f9df26dSmartijn 				index->axv_idata.avb_int32 = INT32_MAX;
29040f9df26dSmartijn 			else if (j >= oid->aoi_idlen || overflow == -1)
29050f9df26dSmartijn 				index->axv_idata.avb_int32 = 0;
29060f9df26dSmartijn 			else {
29070f9df26dSmartijn 				if (oid->aoi_id[j] > INT32_MAX) {
29080f9df26dSmartijn 					index->axv_idata.avb_int32 = INT32_MAX;
290981180db9Smartijn 					overflow = 1;
29100f9df26dSmartijn 				} else
29110f9df26dSmartijn 					index->axv_idata.avb_int32 =
29120f9df26dSmartijn 					    oid->aoi_id[j];
291381180db9Smartijn 			}
291481180db9Smartijn 			break;
291581180db9Smartijn 		case AX_DATA_TYPE_OCTETSTRING:
29160f9df26dSmartijn 			if (overflow == 1) {
29170f9df26dSmartijn 				data->avb_ostring.aos_slen = UINT32_MAX;
29180f9df26dSmartijn 				data->avb_ostring.aos_string = NULL;
29190f9df26dSmartijn 				continue;
29200f9df26dSmartijn 			} else if (j >= oid->aoi_idlen || overflow == -1) {
29210f9df26dSmartijn 				data->avb_ostring.aos_slen = 0;
29220f9df26dSmartijn 				data->avb_ostring.aos_string = NULL;
29230f9df26dSmartijn 				continue;
29240f9df26dSmartijn 			}
29250f9df26dSmartijn 			if (agentx_object_implied(axo, index->axv_axi))
29260f9df26dSmartijn 				data->avb_ostring.aos_slen = oid->aoi_idlen - j;
29270f9df26dSmartijn 			else {
29280f9df26dSmartijn 				data->avb_ostring.aos_slen = oid->aoi_id[j++];
29290f9df26dSmartijn 				if (data->avb_ostring.aos_slen >=
29300f9df26dSmartijn 				    AGENTX_OID_MAX_LEN - j) {
29310f9df26dSmartijn 					data->avb_ostring.aos_slen = UINT32_MAX;
293281180db9Smartijn 					overflow = 1;
293381180db9Smartijn 				}
293481180db9Smartijn 			}
29350f9df26dSmartijn 			if (data->avb_ostring.aos_slen == UINT32_MAX ||
29360f9df26dSmartijn 			    data->avb_ostring.aos_slen == 0) {
29370f9df26dSmartijn 				data->avb_ostring.aos_string = NULL;
29380f9df26dSmartijn 				continue;
293981180db9Smartijn 			}
294081180db9Smartijn 			data->avb_ostring.aos_string =
29410f9df26dSmartijn 			    malloc(data->avb_ostring.aos_slen + 1);
294281180db9Smartijn 			if (data->avb_ostring.aos_string == NULL) {
294381180db9Smartijn 				agentx_log_axg_warn(axg,
294481180db9Smartijn 				    "Failed to bind string index");
294581180db9Smartijn 				agentx_varbind_error_type(axv,
294681180db9Smartijn 				    AX_PDU_ERROR_PROCESSINGERROR, 1);
294781180db9Smartijn 				return;
294881180db9Smartijn 			}
294981180db9Smartijn 			for (k = 0; k < data->avb_ostring.aos_slen; k++, j++) {
29500f9df26dSmartijn 				if (j < oid->aoi_idlen && oid->aoi_id[j] > 0xff)
295181180db9Smartijn 					overflow = 1;
29520f9df26dSmartijn 				if (overflow == 1)
29530f9df26dSmartijn 					data->avb_ostring.aos_string[k] = 0xff;
29540f9df26dSmartijn 				else if (j >= oid->aoi_idlen || overflow == -1)
29550f9df26dSmartijn 					data->avb_ostring.aos_string[k] = '\0';
29560f9df26dSmartijn 				else
29570f9df26dSmartijn 					data->avb_ostring.aos_string[k] =
29580f9df26dSmartijn 					    oid->aoi_id[j];
295981180db9Smartijn 			}
29600f9df26dSmartijn 			data->avb_ostring.aos_string[k] = '\0';
29610f9df26dSmartijn 			j--;
296281180db9Smartijn 			break;
296381180db9Smartijn 		case AX_DATA_TYPE_OID:
29640f9df26dSmartijn 			if (overflow == 1) {
29650f9df26dSmartijn 				data->avb_oid.aoi_idlen = UINT32_MAX;
29660f9df26dSmartijn 				continue;
29670f9df26dSmartijn 			} else if (j >= oid->aoi_idlen || overflow == -1) {
29680f9df26dSmartijn 				data->avb_oid.aoi_idlen = 0;
29690f9df26dSmartijn 				continue;
29700f9df26dSmartijn 			}
29710f9df26dSmartijn 			if (agentx_object_implied(axo, index->axv_axi))
29720f9df26dSmartijn 				data->avb_oid.aoi_idlen = oid->aoi_idlen - j;
29730f9df26dSmartijn 			else {
29740f9df26dSmartijn 				data->avb_oid.aoi_idlen = oid->aoi_id[j++];
29750f9df26dSmartijn 				if (data->avb_oid.aoi_idlen >=
29760f9df26dSmartijn 				    AGENTX_OID_MAX_LEN - j) {
29770f9df26dSmartijn 					data->avb_oid.aoi_idlen = UINT32_MAX;
297881180db9Smartijn 					overflow = 1;
29790f9df26dSmartijn 				}
29800f9df26dSmartijn 			}
29810f9df26dSmartijn 			if (data->avb_oid.aoi_idlen == UINT32_MAX ||
29820f9df26dSmartijn 			    data->avb_oid.aoi_idlen == 0)
298381180db9Smartijn 				continue;
298481180db9Smartijn 			for (k = 0; k < data->avb_oid.aoi_idlen; k++, j++) {
29850f9df26dSmartijn 				if (overflow == 1)
29860f9df26dSmartijn 					data->avb_oid.aoi_id[k] = UINT32_MAX;
29870f9df26dSmartijn 				else if (j >= oid->aoi_idlen || overflow == -1)
298881180db9Smartijn 					data->avb_oid.aoi_id[k] = 0;
29890f9df26dSmartijn 				else
29900f9df26dSmartijn 					data->avb_oid.aoi_id[k] =
29910f9df26dSmartijn 					    oid->aoi_id[j];
299281180db9Smartijn 			}
29930f9df26dSmartijn 			j--;
299481180db9Smartijn 			break;
299581180db9Smartijn 		case AX_DATA_TYPE_IPADDRESS:
29960f9df26dSmartijn 			ipaddress = malloc(sizeof(*ipaddress));
299781180db9Smartijn 			if (ipaddress == NULL) {
299881180db9Smartijn 				agentx_log_axg_warn(axg,
299981180db9Smartijn 				    "Failed to bind ipaddress index");
300081180db9Smartijn 				agentx_varbind_error_type(axv,
300181180db9Smartijn 				    AX_PDU_ERROR_PROCESSINGERROR, 1);
300281180db9Smartijn 				return;
300381180db9Smartijn 			}
300481180db9Smartijn 			ipbytes = (unsigned char *)ipaddress;
300581180db9Smartijn 			for (k = 0; k < 4; k++, j++) {
30060f9df26dSmartijn 				if (j < oid->aoi_idlen && oid->aoi_id[j] > 255)
300781180db9Smartijn 					overflow = 1;
30080f9df26dSmartijn 				if (overflow == 1)
30090f9df26dSmartijn 					ipbytes[k] = 255;
30100f9df26dSmartijn 				else if (j >= oid->aoi_idlen || overflow == -1)
30110f9df26dSmartijn 					ipbytes[k] = 0;
30120f9df26dSmartijn 				else
30130f9df26dSmartijn 					ipbytes[k] = oid->aoi_id[j];
301481180db9Smartijn 			}
30150f9df26dSmartijn 			j--;
301681180db9Smartijn 			data->avb_ostring.aos_slen = sizeof(*ipaddress);
301781180db9Smartijn 			data->avb_ostring.aos_string =
301881180db9Smartijn 			    (unsigned char *)ipaddress;
301981180db9Smartijn 			break;
302081180db9Smartijn 		default:
302181180db9Smartijn #ifdef AX_DEBUG
302281180db9Smartijn 			agentx_log_axg_fatalx(axg,
302381180db9Smartijn 			    "%s: unexpected index type", __func__);
302481180db9Smartijn #else
302581180db9Smartijn 			agentx_log_axg_warnx(axg,
302681180db9Smartijn 			    "%s: unexpected index type", __func__);
302781180db9Smartijn 			agentx_varbind_error_type(axv,
302881180db9Smartijn 			    AX_PDU_ERROR_PROCESSINGERROR, 1);
302981180db9Smartijn 			return;
303081180db9Smartijn #endif
303181180db9Smartijn 		}
303281180db9Smartijn 	}
303381180db9Smartijn 	if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
30340f9df26dSmartijn 		if (j != oid->aoi_idlen || overflow) {
303581180db9Smartijn 			agentx_varbind_nosuchinstance(axv);
303681180db9Smartijn 			return;
303781180db9Smartijn 		}
303881180db9Smartijn 	}
303981180db9Smartijn 
30400f9df26dSmartijn 	if (overflow == 1) {
304181180db9Smartijn 		axv->axv_include = 0;
30420f9df26dSmartijn 	} else if (overflow == -1) {
30430f9df26dSmartijn 		axv->axv_include = 1;
30440f9df26dSmartijn 	} else if (j < oid->aoi_idlen)
30450f9df26dSmartijn 		axv->axv_include = 0;
30460f9df26dSmartijn 	else if (j > oid->aoi_idlen)
30470f9df26dSmartijn 		axv->axv_include = 1;
304881180db9Smartijn 	if (agentx_varbind_request(axv) == AGENTX_REQUEST_TYPE_GETNEXT &&
304981180db9Smartijn 	    !dynamic) {
305081180db9Smartijn 		agentx_varbind_endofmibview(axv);
305181180db9Smartijn 		return;
305281180db9Smartijn 	}
305381180db9Smartijn 
305481180db9Smartijn 	axo->axo_get(axv);
305581180db9Smartijn }
305681180db9Smartijn 
305781180db9Smartijn void
30581b6ededeSmartijn agentx_varbind_integer(struct agentx_varbind *axv, int32_t value)
305981180db9Smartijn {
306081180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_INTEGER;
30611b6ededeSmartijn 	axv->axv_vb.avb_data.avb_int32 = value;
306281180db9Smartijn 
306381180db9Smartijn 	agentx_varbind_finalize(axv);
306481180db9Smartijn }
306581180db9Smartijn 
306681180db9Smartijn void
306781180db9Smartijn agentx_varbind_string(struct agentx_varbind *axv, const char *value)
306881180db9Smartijn {
306981180db9Smartijn 	agentx_varbind_nstring(axv, (const unsigned char *)value,
307081180db9Smartijn 	    strlen(value));
307181180db9Smartijn }
307281180db9Smartijn 
307381180db9Smartijn void
307481180db9Smartijn agentx_varbind_nstring(struct agentx_varbind *axv,
307581180db9Smartijn     const unsigned char *value, size_t slen)
307681180db9Smartijn {
307781180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(slen);
307881180db9Smartijn 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
307981180db9Smartijn 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
308081180db9Smartijn 		agentx_varbind_error_type(axv,
308181180db9Smartijn 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
308281180db9Smartijn 		return;
308381180db9Smartijn 	}
308481180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
308581180db9Smartijn 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, slen);
308681180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_slen = slen;
308781180db9Smartijn 
308881180db9Smartijn 	agentx_varbind_finalize(axv);
308981180db9Smartijn }
309081180db9Smartijn 
309181180db9Smartijn void
309281180db9Smartijn agentx_varbind_printf(struct agentx_varbind *axv, const char *fmt, ...)
309381180db9Smartijn {
309481180db9Smartijn 	va_list ap;
309581180db9Smartijn 	int r;
309681180db9Smartijn 
309781180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
309881180db9Smartijn 	va_start(ap, fmt);
309981180db9Smartijn 	r = vasprintf((char **)&(axv->axv_vb.avb_data.avb_ostring.aos_string),
310081180db9Smartijn 	    fmt, ap);
310181180db9Smartijn 	va_end(ap);
310281180db9Smartijn 	if (r == -1) {
310381180db9Smartijn 		axv->axv_vb.avb_data.avb_ostring.aos_string = NULL;
310481180db9Smartijn 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
31059c70cf54Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
310681180db9Smartijn 		return;
310781180db9Smartijn 	}
310881180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_slen = r;
310981180db9Smartijn 
311081180db9Smartijn 	agentx_varbind_finalize(axv);
311181180db9Smartijn }
311281180db9Smartijn 
311381180db9Smartijn void
311481180db9Smartijn agentx_varbind_null(struct agentx_varbind *axv)
311581180db9Smartijn {
311681180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
311781180db9Smartijn 
311881180db9Smartijn 	agentx_varbind_finalize(axv);
311981180db9Smartijn }
312081180db9Smartijn 
312181180db9Smartijn void
312281180db9Smartijn agentx_varbind_oid(struct agentx_varbind *axv, const uint32_t oid[],
312381180db9Smartijn     size_t oidlen)
312481180db9Smartijn {
31259c70cf54Smartijn 	const char *errstr;
312681180db9Smartijn 
312781180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_OID;
312881180db9Smartijn 
31299c70cf54Smartijn 	if (agentx_oidfill(&(axv->axv_vb.avb_data.avb_oid),
31309c70cf54Smartijn 	    oid, oidlen, &errstr) == -1) {
31319c70cf54Smartijn #ifdef AX_DEBUG
31329c70cf54Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "%s: %s", __func__, errstr);
31339c70cf54Smartijn #else
31349c70cf54Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "%s: %s", __func__, errstr);
31359c70cf54Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
31369c70cf54Smartijn 		return;
31379c70cf54Smartijn #endif
31389c70cf54Smartijn 	}
313981180db9Smartijn 
314081180db9Smartijn 	agentx_varbind_finalize(axv);
314181180db9Smartijn }
314281180db9Smartijn 
314381180db9Smartijn void
314481180db9Smartijn agentx_varbind_object(struct agentx_varbind *axv,
314581180db9Smartijn     struct agentx_object *axo)
314681180db9Smartijn {
314781180db9Smartijn 	agentx_varbind_oid(axv, axo->axo_oid.aoi_id,
314881180db9Smartijn 	    axo->axo_oid.aoi_idlen);
314981180db9Smartijn }
315081180db9Smartijn 
315181180db9Smartijn void
315281180db9Smartijn agentx_varbind_index(struct agentx_varbind *axv,
315381180db9Smartijn     struct agentx_index *axi)
315481180db9Smartijn {
315581180db9Smartijn 	agentx_varbind_oid(axv, axi->axi_vb.avb_oid.aoi_id,
315681180db9Smartijn 	    axi->axi_vb.avb_oid.aoi_idlen);
315781180db9Smartijn }
315881180db9Smartijn 
315981180db9Smartijn 
316081180db9Smartijn void
316181180db9Smartijn agentx_varbind_ipaddress(struct agentx_varbind *axv,
316281180db9Smartijn     const struct in_addr *value)
316381180db9Smartijn {
316481180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_IPADDRESS;
316581180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(4);
316681180db9Smartijn 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
316781180db9Smartijn 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind ipaddress");
316881180db9Smartijn 		agentx_varbind_error_type(axv,
316981180db9Smartijn 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
317081180db9Smartijn 		return;
317181180db9Smartijn 	}
317281180db9Smartijn 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, 4);
317381180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_slen = 4;
317481180db9Smartijn 
317581180db9Smartijn 	agentx_varbind_finalize(axv);
317681180db9Smartijn }
317781180db9Smartijn 
317881180db9Smartijn void
317981180db9Smartijn agentx_varbind_counter32(struct agentx_varbind *axv, uint32_t value)
318081180db9Smartijn {
318181180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER32;
318281180db9Smartijn 	axv->axv_vb.avb_data.avb_uint32 = value;
318381180db9Smartijn 
318481180db9Smartijn 	agentx_varbind_finalize(axv);
318581180db9Smartijn }
318681180db9Smartijn 
318781180db9Smartijn void
318881180db9Smartijn agentx_varbind_gauge32(struct agentx_varbind *axv, uint32_t value)
318981180db9Smartijn {
319081180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_GAUGE32;
319181180db9Smartijn 	axv->axv_vb.avb_data.avb_uint32 = value;
319281180db9Smartijn 
319381180db9Smartijn 	agentx_varbind_finalize(axv);
319481180db9Smartijn }
319581180db9Smartijn 
319681180db9Smartijn void
3197036f0da0Smartijn agentx_varbind_unsigned32(struct agentx_varbind *axv, uint32_t value)
3198036f0da0Smartijn {
3199036f0da0Smartijn 	agentx_varbind_gauge32(axv, value);
3200036f0da0Smartijn }
3201036f0da0Smartijn 
3202036f0da0Smartijn void
320381180db9Smartijn agentx_varbind_timeticks(struct agentx_varbind *axv, uint32_t value)
320481180db9Smartijn {
320581180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_TIMETICKS;
320681180db9Smartijn 	axv->axv_vb.avb_data.avb_uint32 = value;
320781180db9Smartijn 
320881180db9Smartijn 	agentx_varbind_finalize(axv);
320981180db9Smartijn }
321081180db9Smartijn 
321181180db9Smartijn void
321281180db9Smartijn agentx_varbind_opaque(struct agentx_varbind *axv, const char *string,
321381180db9Smartijn     size_t strlen)
321481180db9Smartijn {
321581180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_OPAQUE;
321681180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(strlen);
321781180db9Smartijn 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
321881180db9Smartijn 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind opaque");
321981180db9Smartijn 		agentx_varbind_error_type(axv,
322081180db9Smartijn 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
322181180db9Smartijn 		return;
322281180db9Smartijn 	}
322381180db9Smartijn 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, string, strlen);
322481180db9Smartijn 	axv->axv_vb.avb_data.avb_ostring.aos_slen = strlen;
322581180db9Smartijn 
322681180db9Smartijn 	agentx_varbind_finalize(axv);
322781180db9Smartijn }
322881180db9Smartijn 
322981180db9Smartijn void
323081180db9Smartijn agentx_varbind_counter64(struct agentx_varbind *axv, uint64_t value)
323181180db9Smartijn {
323281180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER64;
323381180db9Smartijn 	axv->axv_vb.avb_data.avb_uint64 = value;
323481180db9Smartijn 
323581180db9Smartijn 	agentx_varbind_finalize(axv);
323681180db9Smartijn }
323781180db9Smartijn 
323881180db9Smartijn void
323981180db9Smartijn agentx_varbind_notfound(struct agentx_varbind *axv)
324081180db9Smartijn {
324181180db9Smartijn 	if (axv->axv_indexlen == 0) {
324281180db9Smartijn #ifdef AX_DEBUG
324381180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "%s invalid call",
324481180db9Smartijn 		    __func__);
324581180db9Smartijn #else
324681180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "%s invalid call",
324781180db9Smartijn 		    __func__);
324881180db9Smartijn 		agentx_varbind_error_type(axv,
324981180db9Smartijn 		    AX_PDU_ERROR_GENERR, 1);
325081180db9Smartijn #endif
325181180db9Smartijn 	} else if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
325281180db9Smartijn 		agentx_varbind_nosuchinstance(axv);
325381180db9Smartijn 	else
325481180db9Smartijn 		agentx_varbind_endofmibview(axv);
325581180db9Smartijn }
325681180db9Smartijn 
325781180db9Smartijn void
325881180db9Smartijn agentx_varbind_error(struct agentx_varbind *axv)
325981180db9Smartijn {
326081180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 1);
326181180db9Smartijn }
326281180db9Smartijn 
326381180db9Smartijn static void
326481180db9Smartijn agentx_varbind_error_type(struct agentx_varbind *axv,
326581180db9Smartijn     enum ax_pdu_error error, int done)
326681180db9Smartijn {
326781180db9Smartijn 	if (axv->axv_error == AX_PDU_ERROR_NOERROR) {
326881180db9Smartijn 		axv->axv_error = error;
326981180db9Smartijn 	}
327081180db9Smartijn 
327181180db9Smartijn 	if (done) {
327281180db9Smartijn 		axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
327381180db9Smartijn 
327481180db9Smartijn 		agentx_varbind_finalize(axv);
327581180db9Smartijn 	}
327681180db9Smartijn }
327781180db9Smartijn 
327881180db9Smartijn static void
327981180db9Smartijn agentx_varbind_finalize(struct agentx_varbind *axv)
328081180db9Smartijn {
328181180db9Smartijn 	struct agentx_get *axg = axv->axv_axg;
328281180db9Smartijn 	struct ax_oid oid;
328381180db9Smartijn 	union ax_data *data;
328481180db9Smartijn 	size_t i, j;
328581180db9Smartijn 	int cmp;
328681180db9Smartijn 
328781180db9Smartijn 	if (axv->axv_error != AX_PDU_ERROR_NOERROR) {
328881180db9Smartijn 		bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
328981180db9Smartijn 		    sizeof(axv->axv_start));
329081180db9Smartijn 		goto done;
329181180db9Smartijn 	}
329281180db9Smartijn 	bcopy(&(axv->axv_axo->axo_oid), &oid, sizeof(oid));
329381180db9Smartijn 	if (axv->axv_indexlen == 0)
329481180db9Smartijn 		ax_oid_add(&oid, 0);
329581180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
329681180db9Smartijn 		data = &(axv->axv_index[i].axv_idata);
329781180db9Smartijn 		switch (axv->axv_index[i].axv_axi->axi_vb.avb_type) {
329881180db9Smartijn 		case AX_DATA_TYPE_INTEGER:
32991b6ededeSmartijn 			if (ax_oid_add(&oid, data->avb_int32) == -1)
330081180db9Smartijn 				goto fail;
330181180db9Smartijn 			break;
330281180db9Smartijn 		case AX_DATA_TYPE_OCTETSTRING:
330381180db9Smartijn 			if (!agentx_object_implied(axv->axv_axo,
330481180db9Smartijn 			    axv->axv_index[i].axv_axi)) {
330581180db9Smartijn 				if (ax_oid_add(&oid,
330681180db9Smartijn 				    data->avb_ostring.aos_slen) == -1)
330781180db9Smartijn 					goto fail;
330881180db9Smartijn 			}
330981180db9Smartijn 			for (j = 0; j < data->avb_ostring.aos_slen; j++) {
331081180db9Smartijn 				if (ax_oid_add(&oid,
331181180db9Smartijn 				    (uint8_t)data->avb_ostring.aos_string[j]) ==
331281180db9Smartijn 				    -1)
331381180db9Smartijn 					goto fail;
331481180db9Smartijn 			}
331581180db9Smartijn 			break;
331681180db9Smartijn 		case AX_DATA_TYPE_OID:
331781180db9Smartijn 			if (!agentx_object_implied(axv->axv_axo,
331881180db9Smartijn 			    axv->axv_index[i].axv_axi)) {
331981180db9Smartijn 				if (ax_oid_add(&oid,
332081180db9Smartijn 				    data->avb_oid.aoi_idlen) == -1)
332181180db9Smartijn 					goto fail;
332281180db9Smartijn 			}
332381180db9Smartijn 			for (j = 0; j < data->avb_oid.aoi_idlen; j++) {
332481180db9Smartijn 				if (ax_oid_add(&oid,
332581180db9Smartijn 				    data->avb_oid.aoi_id[j]) == -1)
332681180db9Smartijn 					goto fail;
332781180db9Smartijn 			}
332881180db9Smartijn 			break;
332981180db9Smartijn 		case AX_DATA_TYPE_IPADDRESS:
333081180db9Smartijn 			for (j = 0; j < 4; j++) {
333181180db9Smartijn 				if (ax_oid_add(&oid,
333281180db9Smartijn 				    data->avb_ostring.aos_string == NULL ? 0 :
333381180db9Smartijn 				    (uint8_t)data->avb_ostring.aos_string[j]) ==
333481180db9Smartijn 				    -1)
333581180db9Smartijn 					goto fail;
333681180db9Smartijn 			}
333781180db9Smartijn 			break;
333881180db9Smartijn 		default:
333981180db9Smartijn #ifdef AX_DEBUG
334081180db9Smartijn 			agentx_log_axg_fatalx(axg,
334181180db9Smartijn 			    "%s: unsupported index type", __func__);
334281180db9Smartijn #else
334381180db9Smartijn 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
334481180db9Smartijn 			    sizeof(axv->axv_start));
334581180db9Smartijn 			axv->axv_error = AX_PDU_ERROR_PROCESSINGERROR;
334681180db9Smartijn 			agentx_object_unlock(axv->axv_axo);
334781180db9Smartijn 			agentx_get_finalize(axv->axv_axg);
334881180db9Smartijn 			return;
334981180db9Smartijn #endif
335081180db9Smartijn 		}
335181180db9Smartijn 	}
3352*c5fcbd5aSmartijn 	cmp = ax_oid_cmp(&oid, &(axv->axv_vb.avb_oid));
3353*c5fcbd5aSmartijn 	switch (agentx_varbind_request(axv)) {
3354*c5fcbd5aSmartijn 	case AGENTX_REQUEST_TYPE_GET:
3355*c5fcbd5aSmartijn 		if (cmp != 0) {
3356*c5fcbd5aSmartijn #ifdef AX_DEBUG
3357*c5fcbd5aSmartijn 			agentx_log_axg_fatalx(axg, "index changed");
3358*c5fcbd5aSmartijn #else
3359*c5fcbd5aSmartijn 			agentx_log_axg_warnx(axg, "index changed");
3360*c5fcbd5aSmartijn 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3361*c5fcbd5aSmartijn 			    sizeof(axv->axv_start));
3362*c5fcbd5aSmartijn 			axv->axv_error = AX_PDU_ERROR_GENERR;
3363*c5fcbd5aSmartijn 			break;
3364*c5fcbd5aSmartijn #endif
3365*c5fcbd5aSmartijn 		}
3366*c5fcbd5aSmartijn 		break;
3367*c5fcbd5aSmartijn 	case AGENTX_REQUEST_TYPE_GETNEXT:
3368*c5fcbd5aSmartijn 		if (cmp <= 0) {
336981180db9Smartijn #ifdef AX_DEBUG
337081180db9Smartijn 			agentx_log_axg_fatalx(axg, "indices not incremented");
337181180db9Smartijn #else
337281180db9Smartijn 			agentx_log_axg_warnx(axg, "indices not incremented");
337381180db9Smartijn 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
337481180db9Smartijn 			    sizeof(axv->axv_start));
337581180db9Smartijn 			axv->axv_error = AX_PDU_ERROR_GENERR;
3376*c5fcbd5aSmartijn 			break;
337781180db9Smartijn #endif
3378*c5fcbd5aSmartijn 		}
3379*c5fcbd5aSmartijn 		/* FALLTHROUGH */
3380*c5fcbd5aSmartijn 	case AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE:
3381*c5fcbd5aSmartijn 		if (cmp < 0) {
3382*c5fcbd5aSmartijn #ifdef AX_DEBUG
3383*c5fcbd5aSmartijn 			agentx_log_axg_fatalx(axg, "index decremented");
3384*c5fcbd5aSmartijn #else
3385*c5fcbd5aSmartijn 			agentx_log_axg_warnx(axg, "index decremented");
3386*c5fcbd5aSmartijn 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3387*c5fcbd5aSmartijn 			    sizeof(axv->axv_start));
3388*c5fcbd5aSmartijn 			axv->axv_error = AX_PDU_ERROR_GENERR;
3389*c5fcbd5aSmartijn 			break;
3390*c5fcbd5aSmartijn #endif
3391*c5fcbd5aSmartijn 		}
3392*c5fcbd5aSmartijn 		if (axv->axv_end.aoi_idlen != 0 &&
3393*c5fcbd5aSmartijn 		    ax_oid_cmp(&oid, &(axv->axv_end)) >= 0) {
3394*c5fcbd5aSmartijn 			agentx_varbind_endofmibview(axv);
3395*c5fcbd5aSmartijn 			return;
3396*c5fcbd5aSmartijn 		}
339781180db9Smartijn 		bcopy(&oid, &(axv->axv_vb.avb_oid), sizeof(oid));
3398*c5fcbd5aSmartijn 	}
339981180db9Smartijn done:
340081180db9Smartijn 	agentx_object_unlock(axv->axv_axo);
340181180db9Smartijn 	agentx_get_finalize(axv->axv_axg);
340281180db9Smartijn 	return;
34039dbe2cd1Smartijn 
34049dbe2cd1Smartijn fail:
340581180db9Smartijn 	agentx_log_axg_warnx(axg, "oid too large");
340681180db9Smartijn 	bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
340781180db9Smartijn 	    sizeof(axv->axv_start));
340881180db9Smartijn 	axv->axv_error = AX_PDU_ERROR_GENERR;
340981180db9Smartijn 	agentx_object_unlock(axv->axv_axo);
341081180db9Smartijn 	agentx_get_finalize(axv->axv_axg);
341181180db9Smartijn }
341281180db9Smartijn 
341381180db9Smartijn static void
341481180db9Smartijn agentx_varbind_nosuchobject(struct agentx_varbind *axv)
341581180db9Smartijn {
341681180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHOBJECT;
341781180db9Smartijn 
341881180db9Smartijn 	if (axv->axv_axo != NULL)
341981180db9Smartijn 		agentx_object_unlock(axv->axv_axo);
342081180db9Smartijn 	agentx_get_finalize(axv->axv_axg);
342181180db9Smartijn }
342281180db9Smartijn 
342381180db9Smartijn static void
342481180db9Smartijn agentx_varbind_nosuchinstance(struct agentx_varbind *axv)
342581180db9Smartijn {
342681180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHINSTANCE;
342781180db9Smartijn 
342881180db9Smartijn 	if (axv->axv_axo != NULL)
342981180db9Smartijn 		agentx_object_unlock(axv->axv_axo);
343081180db9Smartijn 	agentx_get_finalize(axv->axv_axg);
343181180db9Smartijn }
343281180db9Smartijn 
343381180db9Smartijn static void
343481180db9Smartijn agentx_varbind_endofmibview(struct agentx_varbind *axv)
343581180db9Smartijn {
343681180db9Smartijn 	struct agentx_object *axo;
343781180db9Smartijn 	struct ax_varbind *vb;
343881180db9Smartijn 	struct agentx_varbind_index *index;
343981180db9Smartijn 	size_t i;
344081180db9Smartijn 
344181180db9Smartijn #ifdef AX_DEBUG
344281180db9Smartijn 	if (axv->axv_axg->axg_type != AX_PDU_TYPE_GETNEXT &&
344381180db9Smartijn 	    axv->axv_axg->axg_type != AX_PDU_TYPE_GETBULK)
344481180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg,
344581180db9Smartijn 		    "%s: invalid request type", __func__);
344681180db9Smartijn #endif
344781180db9Smartijn 
344881180db9Smartijn 	if (axv->axv_axo != NULL &&
344981180db9Smartijn 	    (axo = RB_NEXT(axc_objects, &(axc->axc_objects),
345081180db9Smartijn 	    axv->axv_axo)) != NULL &&
345181180db9Smartijn 	    ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) < 0) {
345281180db9Smartijn 		bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
345381180db9Smartijn 		    sizeof(axo->axo_oid));
345481180db9Smartijn 		axv->axv_include = 1;
345581180db9Smartijn 		for (i = 0; i < axv->axv_indexlen; i++) {
345681180db9Smartijn 			index = &(axv->axv_index[i]);
345781180db9Smartijn 			vb = &(index->axv_axi->axi_vb);
345881180db9Smartijn 			if (vb->avb_type == AX_DATA_TYPE_OCTETSTRING ||
345981180db9Smartijn 			    vb->avb_type == AX_DATA_TYPE_IPADDRESS)
346081180db9Smartijn 				free(index->axv_idata.avb_ostring.aos_string);
346181180db9Smartijn 		}
346281180db9Smartijn 		bzero(&(axv->axv_index), sizeof(axv->axv_index));
346381180db9Smartijn 		agentx_object_unlock(axv->axv_axo);
346481180db9Smartijn 		agentx_varbind_start(axv);
346581180db9Smartijn 		return;
346681180db9Smartijn 	}
346781180db9Smartijn 
3468c812f9ceSmartijn 	bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3469c812f9ceSmartijn 	    sizeof(axv->axv_start));
347081180db9Smartijn 	axv->axv_vb.avb_type = AX_DATA_TYPE_ENDOFMIBVIEW;
347181180db9Smartijn 
347281180db9Smartijn 	if (axv->axv_axo != NULL)
347381180db9Smartijn 		agentx_object_unlock(axv->axv_axo);
347481180db9Smartijn 	agentx_get_finalize(axv->axv_axg);
347581180db9Smartijn }
347681180db9Smartijn 
347781180db9Smartijn enum agentx_request_type
347881180db9Smartijn agentx_varbind_request(struct agentx_varbind *axv)
347981180db9Smartijn {
348081180db9Smartijn 	if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
348181180db9Smartijn 		return AGENTX_REQUEST_TYPE_GET;
34820f9df26dSmartijn 	if (axv->axv_include)
348381180db9Smartijn 		return AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE;
348481180db9Smartijn 	return AGENTX_REQUEST_TYPE_GETNEXT;
348581180db9Smartijn }
348681180db9Smartijn 
348781180db9Smartijn struct agentx_object *
348881180db9Smartijn agentx_varbind_get_object(struct agentx_varbind *axv)
348981180db9Smartijn {
349081180db9Smartijn 	return axv->axv_axo;
349181180db9Smartijn }
349281180db9Smartijn 
34931b6ededeSmartijn int32_t
349481180db9Smartijn agentx_varbind_get_index_integer(struct agentx_varbind *axv,
349581180db9Smartijn     struct agentx_index *axi)
349681180db9Smartijn {
349781180db9Smartijn 	size_t i;
349881180db9Smartijn 
349981180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
350081180db9Smartijn #ifdef AX_DEBUG
350181180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
350281180db9Smartijn #else
350381180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
350481180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
350581180db9Smartijn 		return 0;
350681180db9Smartijn #endif
350781180db9Smartijn 	}
350881180db9Smartijn 
350981180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
351081180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi)
35111b6ededeSmartijn 			return axv->axv_index[i].axv_idata.avb_int32;
351281180db9Smartijn 	}
351381180db9Smartijn #ifdef AX_DEBUG
351481180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
351581180db9Smartijn #else
351681180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
351781180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
351881180db9Smartijn 	return 0;
351981180db9Smartijn #endif
352081180db9Smartijn }
352181180db9Smartijn 
352281180db9Smartijn const unsigned char *
352381180db9Smartijn agentx_varbind_get_index_string(struct agentx_varbind *axv,
352481180db9Smartijn     struct agentx_index *axi, size_t *slen, int *implied)
352581180db9Smartijn {
352681180db9Smartijn 	struct agentx_varbind_index *index;
352781180db9Smartijn 	size_t i;
352881180db9Smartijn 
352981180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
353081180db9Smartijn #ifdef AX_DEBUG
353181180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
353281180db9Smartijn #else
353381180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
353481180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
353581180db9Smartijn 		*slen = 0;
353681180db9Smartijn 		*implied = 0;
353781180db9Smartijn 		return NULL;
353881180db9Smartijn #endif
353981180db9Smartijn 	}
354081180db9Smartijn 
354181180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
354281180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
354381180db9Smartijn 			index = &(axv->axv_index[i]);
354481180db9Smartijn 			*slen = index->axv_idata.avb_ostring.aos_slen;
354581180db9Smartijn 			*implied = agentx_object_implied(axv->axv_axo, axi);
354681180db9Smartijn 			return index->axv_idata.avb_ostring.aos_string;
354781180db9Smartijn 		}
354881180db9Smartijn 	}
354981180db9Smartijn 
355081180db9Smartijn #ifdef AX_DEBUG
355181180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
355281180db9Smartijn #else
355381180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
355481180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
355581180db9Smartijn 	*slen = 0;
355681180db9Smartijn 	*implied = 0;
355781180db9Smartijn 	return NULL;
355881180db9Smartijn #endif
355981180db9Smartijn }
356081180db9Smartijn 
356181180db9Smartijn const uint32_t *
356281180db9Smartijn agentx_varbind_get_index_oid(struct agentx_varbind *axv,
356381180db9Smartijn     struct agentx_index *axi, size_t *oidlen, int *implied)
356481180db9Smartijn {
356581180db9Smartijn 	struct agentx_varbind_index *index;
356681180db9Smartijn 	size_t i;
356781180db9Smartijn 
356881180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
356981180db9Smartijn #ifdef AX_DEBUG
357081180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
357181180db9Smartijn #else
357281180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
357381180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
357481180db9Smartijn 		*oidlen = 0;
357581180db9Smartijn 		*implied = 0;
357681180db9Smartijn 		return NULL;
357781180db9Smartijn #endif
357881180db9Smartijn 	}
357981180db9Smartijn 
358081180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
358181180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
358281180db9Smartijn 			index = &(axv->axv_index[i]);
358381180db9Smartijn 			*oidlen = index->axv_idata.avb_oid.aoi_idlen;
358481180db9Smartijn 			*implied = agentx_object_implied(axv->axv_axo, axi);
358581180db9Smartijn 			return index->axv_idata.avb_oid.aoi_id;
358681180db9Smartijn 		}
358781180db9Smartijn 	}
358881180db9Smartijn 
358981180db9Smartijn #ifdef AX_DEBUG
359081180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
359181180db9Smartijn #else
359281180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
359381180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
359481180db9Smartijn 	*oidlen = 0;
359581180db9Smartijn 	*implied = 0;
359681180db9Smartijn 	return NULL;
359781180db9Smartijn #endif
359881180db9Smartijn }
359981180db9Smartijn 
360081180db9Smartijn const struct in_addr *
360181180db9Smartijn agentx_varbind_get_index_ipaddress(struct agentx_varbind *axv,
360281180db9Smartijn     struct agentx_index *axi)
360381180db9Smartijn {
360481180db9Smartijn 	static struct in_addr nuladdr = {0};
360581180db9Smartijn 	struct agentx_varbind_index *index;
360681180db9Smartijn 	size_t i;
360781180db9Smartijn 
360881180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
360981180db9Smartijn #ifdef AX_DEBUG
361081180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
361181180db9Smartijn #else
361281180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
361381180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
361481180db9Smartijn 		return NULL;
361581180db9Smartijn #endif
361681180db9Smartijn 	}
361781180db9Smartijn 
361881180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
361981180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
362081180db9Smartijn 			index = &(axv->axv_index[i]);
362181180db9Smartijn 			if (index->axv_idata.avb_ostring.aos_string == NULL)
362281180db9Smartijn 				return &nuladdr;
362381180db9Smartijn 			return (struct in_addr *)
362481180db9Smartijn 			    index->axv_idata.avb_ostring.aos_string;
362581180db9Smartijn 		}
362681180db9Smartijn 	}
362781180db9Smartijn 
362881180db9Smartijn #ifdef AX_DEBUG
362981180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
363081180db9Smartijn #else
363181180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
363281180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
363381180db9Smartijn 	return NULL;
363481180db9Smartijn #endif
363581180db9Smartijn }
363681180db9Smartijn 
363781180db9Smartijn void
363881180db9Smartijn agentx_varbind_set_index_integer(struct agentx_varbind *axv,
36391b6ededeSmartijn     struct agentx_index *axi, int32_t value)
364081180db9Smartijn {
364181180db9Smartijn 	size_t i;
364281180db9Smartijn 
364381180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
364481180db9Smartijn #ifdef AX_DEBUG
364581180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
364681180db9Smartijn #else
364781180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
364881180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
364981180db9Smartijn 		return;
365081180db9Smartijn #endif
365181180db9Smartijn 	}
365281180db9Smartijn 
36531b6ededeSmartijn 	if (value < 0) {
36541b6ededeSmartijn #ifdef AX_DEBUG
36551b6ededeSmartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index value");
36561b6ededeSmartijn #else
36571b6ededeSmartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index value");
36581b6ededeSmartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
36591b6ededeSmartijn 		return;
36601b6ededeSmartijn #endif
36611b6ededeSmartijn 	}
36621b6ededeSmartijn 
366381180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
366481180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
366581180db9Smartijn 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
36661b6ededeSmartijn 			    axv->axv_index[i].axv_idata.avb_int32 != value) {
366781180db9Smartijn #ifdef AX_DEBUG
366881180db9Smartijn 				agentx_log_axg_fatalx(axv->axv_axg,
366981180db9Smartijn 				    "can't change index on GET");
367081180db9Smartijn #else
367181180db9Smartijn 				agentx_log_axg_warnx(axv->axv_axg,
367281180db9Smartijn 				    "can't change index on GET");
367381180db9Smartijn 				agentx_varbind_error_type(axv,
367481180db9Smartijn 				    AX_PDU_ERROR_GENERR, 0);
367581180db9Smartijn 				return;
367681180db9Smartijn #endif
367781180db9Smartijn 			}
36781b6ededeSmartijn 			axv->axv_index[i].axv_idata.avb_int32 = value;
367981180db9Smartijn 			return;
368081180db9Smartijn 		}
368181180db9Smartijn 	}
368281180db9Smartijn #ifdef AX_DEBUG
368381180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
368481180db9Smartijn #else
368581180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
368681180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
368781180db9Smartijn #endif
368881180db9Smartijn }
368981180db9Smartijn 
369081180db9Smartijn void
369181180db9Smartijn agentx_varbind_set_index_string(struct agentx_varbind *axv,
369281180db9Smartijn     struct agentx_index *axi, const char *value)
369381180db9Smartijn {
369481180db9Smartijn 	agentx_varbind_set_index_nstring(axv, axi,
369581180db9Smartijn 	    (const unsigned char *)value, strlen(value));
369681180db9Smartijn }
369781180db9Smartijn 
369881180db9Smartijn void
369981180db9Smartijn agentx_varbind_set_index_nstring(struct agentx_varbind *axv,
370081180db9Smartijn     struct agentx_index *axi, const unsigned char *value, size_t slen)
370181180db9Smartijn {
370281180db9Smartijn 	struct ax_ostring *curvalue;
370381180db9Smartijn 	unsigned char *nstring;
370481180db9Smartijn 	size_t i;
370581180db9Smartijn 
370681180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
370781180db9Smartijn #ifdef AX_DEBUG
370881180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
370981180db9Smartijn #else
371081180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
371181180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
371281180db9Smartijn 		return;
371381180db9Smartijn #endif
371481180db9Smartijn 	}
371581180db9Smartijn 
371681180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
371781180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
371881180db9Smartijn 			if (axi->axi_vb.avb_data.avb_ostring.aos_slen != 0 &&
371981180db9Smartijn 			    axi->axi_vb.avb_data.avb_ostring.aos_slen != slen) {
372081180db9Smartijn #ifdef AX_DEBUG
372181180db9Smartijn 				agentx_log_axg_fatalx(axv->axv_axg,
372281180db9Smartijn 				    "invalid string length on explicit length "
372381180db9Smartijn 				    "string");
372481180db9Smartijn #else
372581180db9Smartijn 				agentx_log_axg_warnx(axv->axv_axg,
372681180db9Smartijn 				    "invalid string length on explicit length "
372781180db9Smartijn 				    "string");
372881180db9Smartijn 				agentx_varbind_error_type(axv,
372981180db9Smartijn 				    AX_PDU_ERROR_GENERR, 0);
373081180db9Smartijn 				return;
373181180db9Smartijn #endif
373281180db9Smartijn 			}
373381180db9Smartijn 			curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
373481180db9Smartijn 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
373581180db9Smartijn 			    (curvalue->aos_slen != slen ||
373681180db9Smartijn 			    memcmp(curvalue->aos_string, value, slen) != 0)) {
373781180db9Smartijn #ifdef AX_DEBUG
373881180db9Smartijn 				agentx_log_axg_fatalx(axv->axv_axg,
373981180db9Smartijn 				    "can't change index on GET");
374081180db9Smartijn #else
374181180db9Smartijn 				agentx_log_axg_warnx(axv->axv_axg,
374281180db9Smartijn 				    "can't change index on GET");
374381180db9Smartijn 				agentx_varbind_error_type(axv,
374481180db9Smartijn 				    AX_PDU_ERROR_GENERR, 0);
374581180db9Smartijn 				return;
374681180db9Smartijn #endif
374781180db9Smartijn 			}
374881180db9Smartijn 			if ((nstring = recallocarray(curvalue->aos_string,
374981180db9Smartijn 			    curvalue->aos_slen + 1, slen + 1, 1)) == NULL) {
375081180db9Smartijn 				agentx_log_axg_warn(axv->axv_axg,
375181180db9Smartijn 				    "Failed to bind string index");
375281180db9Smartijn 				agentx_varbind_error_type(axv,
375381180db9Smartijn 				    AX_PDU_ERROR_PROCESSINGERROR, 0);
375481180db9Smartijn 				return;
375581180db9Smartijn 			}
375681180db9Smartijn 			curvalue->aos_string = nstring;
375781180db9Smartijn 			memcpy(nstring, value, slen);
375881180db9Smartijn 			curvalue->aos_slen = slen;
375981180db9Smartijn 			return;
376081180db9Smartijn 		}
376181180db9Smartijn 	}
376281180db9Smartijn #ifdef AX_DEBUG
376381180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
376481180db9Smartijn #else
376581180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
376681180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
376781180db9Smartijn #endif
376881180db9Smartijn }
376981180db9Smartijn 
377081180db9Smartijn void
377181180db9Smartijn agentx_varbind_set_index_oid(struct agentx_varbind *axv,
377281180db9Smartijn     struct agentx_index *axi, const uint32_t *value, size_t oidlen)
377381180db9Smartijn {
377481180db9Smartijn 	struct ax_oid *curvalue, oid;
37759c70cf54Smartijn 	const char *errstr;
377681180db9Smartijn 	size_t i;
377781180db9Smartijn 
377881180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
377981180db9Smartijn #ifdef AX_DEBUG
378081180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
378181180db9Smartijn #else
378281180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
378381180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
378481180db9Smartijn 		return;
378581180db9Smartijn #endif
378681180db9Smartijn 	}
378781180db9Smartijn 
378881180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
378981180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
379081180db9Smartijn 			if (axi->axi_vb.avb_data.avb_oid.aoi_idlen != 0 &&
379181180db9Smartijn 			    axi->axi_vb.avb_data.avb_oid.aoi_idlen != oidlen) {
379281180db9Smartijn #ifdef AX_DEBUG
379381180db9Smartijn 				agentx_log_axg_fatalx(axv->axv_axg,
379481180db9Smartijn 				    "invalid oid length on explicit length "
379581180db9Smartijn 				    "oid");
379681180db9Smartijn #else
379781180db9Smartijn 				agentx_log_axg_warnx(axv->axv_axg,
379881180db9Smartijn 				    "invalid oid length on explicit length "
379981180db9Smartijn 				    "oid");
380081180db9Smartijn 				agentx_varbind_error_type(axv,
380181180db9Smartijn 				    AX_PDU_ERROR_GENERR, 0);
380281180db9Smartijn 				return;
380381180db9Smartijn #endif
380481180db9Smartijn 			}
380581180db9Smartijn 			curvalue = &(axv->axv_index[i].axv_idata.avb_oid);
38069c70cf54Smartijn 			if (agentx_oidfill(&oid, value,
38079c70cf54Smartijn 			    oidlen, &errstr) == -1) {
38089c70cf54Smartijn #ifdef AX_DEBUG
38099c70cf54Smartijn 				agentx_log_axg_fatalx(axv->axv_axg, "%s: %s",
38109c70cf54Smartijn 				    __func__, errstr);
38119c70cf54Smartijn #else
38129c70cf54Smartijn 				agentx_log_axg_warnx(axv->axv_axg, "%s: %s",
38139c70cf54Smartijn 				     __func__, errstr);
38149c70cf54Smartijn 				agentx_varbind_error_type(axv,
38159c70cf54Smartijn 				     AX_PDU_ERROR_PROCESSINGERROR, 1);
38169c70cf54Smartijn 				return;
38179c70cf54Smartijn #endif
38189c70cf54Smartijn 			}
38199c70cf54Smartijn 
382081180db9Smartijn 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
382181180db9Smartijn 			    ax_oid_cmp(&oid, curvalue) != 0) {
382281180db9Smartijn #ifdef AX_DEBUG
382381180db9Smartijn 				agentx_log_axg_fatalx(axv->axv_axg,
382481180db9Smartijn 				    "can't change index on GET");
382581180db9Smartijn #else
382681180db9Smartijn 				agentx_log_axg_warnx(axv->axv_axg,
382781180db9Smartijn 				    "can't change index on GET");
382881180db9Smartijn 				agentx_varbind_error_type(axv,
382981180db9Smartijn 				    AX_PDU_ERROR_GENERR, 0);
383081180db9Smartijn 				return;
383181180db9Smartijn #endif
383281180db9Smartijn 			}
38339c70cf54Smartijn 
38349c70cf54Smartijn 			*curvalue = oid;
383581180db9Smartijn 			return;
383681180db9Smartijn 		}
383781180db9Smartijn 	}
383881180db9Smartijn #ifdef AX_DEBUG
383981180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
384081180db9Smartijn #else
384181180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
384281180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
384381180db9Smartijn #endif
384481180db9Smartijn }
384581180db9Smartijn 
384681180db9Smartijn void
384781180db9Smartijn agentx_varbind_set_index_object(struct agentx_varbind *axv,
384881180db9Smartijn     struct agentx_index *axi, struct agentx_object *axo)
384981180db9Smartijn {
385081180db9Smartijn 	agentx_varbind_set_index_oid(axv, axi, axo->axo_oid.aoi_id,
385181180db9Smartijn 	    axo->axo_oid.aoi_idlen);
385281180db9Smartijn }
385381180db9Smartijn 
385481180db9Smartijn void
385581180db9Smartijn agentx_varbind_set_index_ipaddress(struct agentx_varbind *axv,
385681180db9Smartijn     struct agentx_index *axi, const struct in_addr *addr)
385781180db9Smartijn {
385881180db9Smartijn 	struct ax_ostring *curvalue;
385981180db9Smartijn 	size_t i;
386081180db9Smartijn 
386181180db9Smartijn 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
386281180db9Smartijn #ifdef AX_DEBUG
386381180db9Smartijn 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
386481180db9Smartijn #else
386581180db9Smartijn 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
386681180db9Smartijn 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
386781180db9Smartijn 		return;
386881180db9Smartijn #endif
386981180db9Smartijn 	}
387081180db9Smartijn 
387181180db9Smartijn 	for (i = 0; i < axv->axv_indexlen; i++) {
387281180db9Smartijn 		if (axv->axv_index[i].axv_axi == axi) {
387381180db9Smartijn 			curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
387481180db9Smartijn 			if (curvalue->aos_string == NULL)
387581180db9Smartijn 				curvalue->aos_string = calloc(1, sizeof(*addr));
387681180db9Smartijn 			if (curvalue->aos_string == NULL) {
387781180db9Smartijn 				agentx_log_axg_warn(axv->axv_axg,
387881180db9Smartijn 				    "Failed to bind ipaddress index");
387981180db9Smartijn 				agentx_varbind_error_type(axv,
388081180db9Smartijn 				    AX_PDU_ERROR_PROCESSINGERROR, 0);
388181180db9Smartijn 				return;
388281180db9Smartijn 			}
388381180db9Smartijn 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
388481180db9Smartijn 			    memcmp(addr, curvalue->aos_string,
388581180db9Smartijn 			    sizeof(*addr)) != 0) {
388681180db9Smartijn #ifdef AX_DEBUG
388781180db9Smartijn 				agentx_log_axg_fatalx(axv->axv_axg,
388881180db9Smartijn 				    "can't change index on GET");
388981180db9Smartijn #else
389081180db9Smartijn 				agentx_log_axg_warnx(axv->axv_axg,
389181180db9Smartijn 				    "can't change index on GET");
389281180db9Smartijn 				agentx_varbind_error_type(axv,
389381180db9Smartijn 				    AX_PDU_ERROR_GENERR, 0);
389481180db9Smartijn 				return;
389581180db9Smartijn #endif
389681180db9Smartijn 			}
389781180db9Smartijn 			bcopy(addr, curvalue->aos_string, sizeof(*addr));
389881180db9Smartijn 			return;
389981180db9Smartijn 		}
390081180db9Smartijn 	}
390181180db9Smartijn #ifdef AX_DEBUG
390281180db9Smartijn 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
390381180db9Smartijn #else
390481180db9Smartijn 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
390581180db9Smartijn 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
390681180db9Smartijn #endif
390781180db9Smartijn }
390881180db9Smartijn 
390981180db9Smartijn static int
391081180db9Smartijn agentx_request(struct agentx *ax, uint32_t packetid,
391181180db9Smartijn     int (*cb)(struct ax_pdu *, void *), void *cookie)
391281180db9Smartijn {
391381180db9Smartijn 	struct agentx_request *axr;
391481180db9Smartijn 
391581180db9Smartijn #ifdef AX_DEBUG
391681180db9Smartijn 	if (ax->ax_ax->ax_wblen == 0)
391781180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: no data to be written",
391881180db9Smartijn 		    __func__);
391981180db9Smartijn #endif
392081180db9Smartijn 
392181180db9Smartijn 	if ((axr = calloc(1, sizeof(*axr))) == NULL) {
392281180db9Smartijn 		agentx_log_ax_warn(ax, "couldn't create request context");
392381180db9Smartijn 		agentx_reset(ax);
39249dbe2cd1Smartijn 		return -1;
39259dbe2cd1Smartijn 	}
392681180db9Smartijn 
392781180db9Smartijn 	axr->axr_packetid = packetid;
392881180db9Smartijn 	axr->axr_cb = cb;
392981180db9Smartijn 	axr->axr_cookie = cookie;
393081180db9Smartijn 	if (RB_INSERT(ax_requests, &(ax->ax_requests), axr) != NULL) {
393181180db9Smartijn #ifdef AX_DEBUG
393281180db9Smartijn 		agentx_log_ax_fatalx(ax, "%s: duplicate packetid", __func__);
393381180db9Smartijn #else
393481180db9Smartijn 		agentx_log_ax_warnx(ax, "%s: duplicate packetid", __func__);
393581180db9Smartijn 		free(axr);
393681180db9Smartijn 		agentx_reset(ax);
393781180db9Smartijn 		return -1;
393881180db9Smartijn #endif
393981180db9Smartijn 	}
394081180db9Smartijn 
394181180db9Smartijn 	agentx_wantwrite(ax, ax->ax_fd);
394281180db9Smartijn 	return 0;
394381180db9Smartijn }
394481180db9Smartijn 
394581180db9Smartijn static int
394681180db9Smartijn agentx_request_cmp(struct agentx_request *r1,
394781180db9Smartijn     struct agentx_request *r2)
394881180db9Smartijn {
394981180db9Smartijn 	return r1->axr_packetid < r2->axr_packetid ? -1 :
395081180db9Smartijn 	    r1->axr_packetid > r2->axr_packetid;
395181180db9Smartijn }
395281180db9Smartijn 
395381180db9Smartijn static int
395481180db9Smartijn agentx_strcat(char **dst, const char *src)
395581180db9Smartijn {
395681180db9Smartijn 	char *tmp;
395781180db9Smartijn 	size_t dstlen = 0, buflen = 0, srclen, nbuflen;
395881180db9Smartijn 
395981180db9Smartijn 	if (*dst != NULL) {
396081180db9Smartijn 		dstlen = strlen(*dst);
396181180db9Smartijn 		buflen = ((dstlen / 512) + 1) * 512;
396281180db9Smartijn 	}
396381180db9Smartijn 
396481180db9Smartijn 	srclen = strlen(src);
396581180db9Smartijn 	if (*dst == NULL || dstlen + srclen > buflen) {
396681180db9Smartijn 		nbuflen = (((dstlen + srclen) / 512) + 1) * 512;
396781180db9Smartijn 		tmp = recallocarray(*dst, buflen, nbuflen, sizeof(*tmp));
396881180db9Smartijn 		if (tmp == NULL)
396981180db9Smartijn 			return -1;
397081180db9Smartijn 		*dst = tmp;
397181180db9Smartijn 		buflen = nbuflen;
397281180db9Smartijn 	}
397381180db9Smartijn 
397481180db9Smartijn 	(void)strlcat(*dst, src, buflen);
397581180db9Smartijn 	return 0;
397681180db9Smartijn }
397781180db9Smartijn 
39789c70cf54Smartijn static int
39799c70cf54Smartijn agentx_oidfill(struct ax_oid *oid, const uint32_t oidval[], size_t oidlen,
39809c70cf54Smartijn     const char **errstr)
39819c70cf54Smartijn {
39829c70cf54Smartijn 	size_t i;
39839c70cf54Smartijn 
39849c70cf54Smartijn 	if (oidlen < AGENTX_OID_MIN_LEN) {
39859c70cf54Smartijn 		*errstr = "oidlen < 2";
39869c70cf54Smartijn 		errno = EINVAL;
39879c70cf54Smartijn 		return -1;
39889c70cf54Smartijn 	}
39899c70cf54Smartijn 	if (oidlen > AGENTX_OID_MAX_LEN) {
39909c70cf54Smartijn 		*errstr = "oidlen > 128";
39919c70cf54Smartijn 		errno = EINVAL;
39929c70cf54Smartijn 		return -1;
39939c70cf54Smartijn 	}
39949c70cf54Smartijn 
39959c70cf54Smartijn 	for (i = 0; i < oidlen; i++)
39969c70cf54Smartijn 		oid->aoi_id[i] = oidval[i];
39979c70cf54Smartijn 	oid->aoi_idlen = oidlen;
39989c70cf54Smartijn 	return 0;
39999c70cf54Smartijn }
40009c70cf54Smartijn 
400181180db9Smartijn void
400281180db9Smartijn agentx_read(struct agentx *ax)
400381180db9Smartijn {
400481180db9Smartijn 	struct agentx_session *axs;
400581180db9Smartijn 	struct agentx_context *axc;
400681180db9Smartijn 	struct agentx_request axr_search, *axr;
400781180db9Smartijn 	struct ax_pdu *pdu;
400881180db9Smartijn 	int error;
400981180db9Smartijn 
401081180db9Smartijn 	if ((pdu = ax_recv(ax->ax_ax)) == NULL) {
401181180db9Smartijn 		if (errno == EAGAIN)
401281180db9Smartijn 			return;
401381180db9Smartijn 		agentx_log_ax_warn(ax, "lost connection");
401481180db9Smartijn 		agentx_reset(ax);
401581180db9Smartijn 		return;
401681180db9Smartijn 	}
401781180db9Smartijn 
401881180db9Smartijn 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
401981180db9Smartijn 		if (axs->axs_id == pdu->ap_header.aph_sessionid)
402081180db9Smartijn 			break;
402181180db9Smartijn 		if (axs->axs_cstate == AX_CSTATE_WAITOPEN &&
402281180db9Smartijn 		    axs->axs_packetid == pdu->ap_header.aph_packetid)
402381180db9Smartijn 			break;
402481180db9Smartijn 	}
402581180db9Smartijn 	if (axs == NULL) {
402681180db9Smartijn 		agentx_log_ax_warnx(ax, "received unexpected session: %d",
402781180db9Smartijn 		    pdu->ap_header.aph_sessionid);
402881180db9Smartijn 		ax_pdu_free(pdu);
402981180db9Smartijn 		agentx_reset(ax);
403081180db9Smartijn 		return;
403181180db9Smartijn 	}
403281180db9Smartijn 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts) {
403381180db9Smartijn 		if ((pdu->ap_header.aph_flags &
403481180db9Smartijn 		    AX_PDU_FLAG_NON_DEFAULT_CONTEXT) == 0 &&
403581180db9Smartijn 		    axc->axc_name_default == 1)
403681180db9Smartijn 			break;
403781180db9Smartijn 		if (pdu->ap_header.aph_flags &
403881180db9Smartijn 		    AX_PDU_FLAG_NON_DEFAULT_CONTEXT &&
403981180db9Smartijn 		    axc->axc_name_default == 0 &&
404081180db9Smartijn 		    pdu->ap_context.aos_slen == axc->axc_name.aos_slen &&
404181180db9Smartijn 		    memcmp(pdu->ap_context.aos_string,
404281180db9Smartijn 		    axc->axc_name.aos_string, axc->axc_name.aos_slen) == 0)
404381180db9Smartijn 			break;
404481180db9Smartijn 	}
404581180db9Smartijn 	if (pdu->ap_header.aph_type != AX_PDU_TYPE_RESPONSE) {
404681180db9Smartijn 		if (axc == NULL) {
404781180db9Smartijn 			agentx_log_ax_warnx(ax, "%s: invalid context",
404881180db9Smartijn 			    pdu->ap_context.aos_string);
404981180db9Smartijn 			ax_pdu_free(pdu);
405081180db9Smartijn 			agentx_reset(ax);
405181180db9Smartijn 			return;
405281180db9Smartijn 		}
405381180db9Smartijn 	}
405481180db9Smartijn 
405581180db9Smartijn 	switch (pdu->ap_header.aph_type) {
405681180db9Smartijn 	case AX_PDU_TYPE_GET:
405781180db9Smartijn 	case AX_PDU_TYPE_GETNEXT:
405881180db9Smartijn 	case AX_PDU_TYPE_GETBULK:
405981180db9Smartijn 		agentx_get_start(axc, pdu);
406081180db9Smartijn 		break;
406181180db9Smartijn 	/* Add stubs for set functions */
406281180db9Smartijn 	case AX_PDU_TYPE_TESTSET:
406381180db9Smartijn 	case AX_PDU_TYPE_COMMITSET:
406481180db9Smartijn 	case AX_PDU_TYPE_UNDOSET:
406581180db9Smartijn 		if (pdu->ap_header.aph_type == AX_PDU_TYPE_TESTSET)
406681180db9Smartijn 			error = AX_PDU_ERROR_NOTWRITABLE;
406781180db9Smartijn 		else if (pdu->ap_header.aph_type == AX_PDU_TYPE_COMMITSET)
406881180db9Smartijn 			error = AX_PDU_ERROR_COMMITFAILED;
406981180db9Smartijn 		else
407081180db9Smartijn 			error = AX_PDU_ERROR_UNDOFAILED;
407181180db9Smartijn 
407281180db9Smartijn 		agentx_log_axc_debug(axc, "unsupported call: %s",
407381180db9Smartijn 		    ax_pdutype2string(pdu->ap_header.aph_type));
407481180db9Smartijn 		if (ax_response(ax->ax_ax, axs->axs_id,
407581180db9Smartijn 		    pdu->ap_header.aph_transactionid,
407681180db9Smartijn 		    pdu->ap_header.aph_packetid,
407781180db9Smartijn 		    0, error, 1, NULL, 0) == -1)
407881180db9Smartijn 			agentx_log_axc_warn(axc,
407981180db9Smartijn 			    "transaction: %u packetid: %u: failed to send "
408081180db9Smartijn 			    "reply", pdu->ap_header.aph_transactionid,
408181180db9Smartijn 			    pdu->ap_header.aph_packetid);
408281180db9Smartijn 		if (ax->ax_ax->ax_wblen > 0)
408381180db9Smartijn 			agentx_wantwrite(ax, ax->ax_fd);
408481180db9Smartijn 		break;
408581180db9Smartijn 	case AX_PDU_TYPE_CLEANUPSET:
408681180db9Smartijn 		agentx_log_ax_debug(ax, "unsupported call: %s",
408781180db9Smartijn 		    ax_pdutype2string(pdu->ap_header.aph_type));
408881180db9Smartijn 		break;
408981180db9Smartijn 	case AX_PDU_TYPE_RESPONSE:
409081180db9Smartijn 		axr_search.axr_packetid = pdu->ap_header.aph_packetid;
409181180db9Smartijn 		axr = RB_FIND(ax_requests, &(ax->ax_requests), &axr_search);
409281180db9Smartijn 		if (axr == NULL) {
409381180db9Smartijn 			if (axc == NULL)
409481180db9Smartijn 				agentx_log_ax_warnx(ax, "received "
409581180db9Smartijn 				    "response on non-request");
409681180db9Smartijn 			else
409781180db9Smartijn 				agentx_log_axc_warnx(axc, "received "
409881180db9Smartijn 				    "response on non-request");
409981180db9Smartijn 			break;
410081180db9Smartijn 		}
410181180db9Smartijn 		if (axc != NULL && pdu->ap_payload.ap_response.ap_error == 0) {
410281180db9Smartijn 			axc->axc_sysuptime =
410381180db9Smartijn 			    pdu->ap_payload.ap_response.ap_uptime;
410481180db9Smartijn 			(void) clock_gettime(CLOCK_MONOTONIC,
410581180db9Smartijn 			    &(axc->axc_sysuptimespec));
410681180db9Smartijn 		}
410781180db9Smartijn 		RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
410881180db9Smartijn 		(void) axr->axr_cb(pdu, axr->axr_cookie);
410981180db9Smartijn 		free(axr);
411081180db9Smartijn 		break;
411181180db9Smartijn 	default:
411281180db9Smartijn 		if (axc == NULL)
411381180db9Smartijn 			agentx_log_ax_warnx(ax, "unsupported call: %s",
411481180db9Smartijn 			    ax_pdutype2string(pdu->ap_header.aph_type));
411581180db9Smartijn 		else
411681180db9Smartijn 			agentx_log_axc_warnx(axc, "unsupported call: %s",
411781180db9Smartijn 			    ax_pdutype2string(pdu->ap_header.aph_type));
411881180db9Smartijn 		agentx_reset(ax);
411981180db9Smartijn 		break;
412081180db9Smartijn 	}
412181180db9Smartijn 	ax_pdu_free(pdu);
412281180db9Smartijn }
412381180db9Smartijn 
412481180db9Smartijn void
412581180db9Smartijn agentx_write(struct agentx *ax)
412681180db9Smartijn {
412781180db9Smartijn 	ssize_t send;
412881180db9Smartijn 
412981180db9Smartijn 	if ((send = ax_send(ax->ax_ax)) == -1) {
413081180db9Smartijn 		if (errno == EAGAIN) {
413181180db9Smartijn 			agentx_wantwrite(ax, ax->ax_fd);
413281180db9Smartijn 			return;
413381180db9Smartijn 		}
413481180db9Smartijn 		agentx_log_ax_warn(ax, "lost connection");
413581180db9Smartijn 		agentx_reset(ax);
413681180db9Smartijn 		return;
413781180db9Smartijn 	}
413881180db9Smartijn 	if (send > 0)
413981180db9Smartijn 		agentx_wantwrite(ax, ax->ax_fd);
414081180db9Smartijn }
414181180db9Smartijn 
414281180db9Smartijn RB_GENERATE_STATIC(ax_requests, agentx_request, axr_ax_requests,
414381180db9Smartijn     agentx_request_cmp)
414481180db9Smartijn RB_GENERATE_STATIC(axc_objects, agentx_object, axo_axc_objects,
414581180db9Smartijn     agentx_object_cmp)
4146