xref: /openbsd/lib/libagentx/agentx.c (revision c5fcbd5a)
1 /*	$OpenBSD: agentx.c,v 1.24 2023/10/29 11:10:07 martijn Exp $ */
2 /*
3  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <netinet/in.h>
18 
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <time.h>
26 #include <unistd.h>
27 
28 #include "agentx_internal.h"
29 #include <agentx.h>
30 
31 /*
32  * ax:		struct agentx
33  * axs:		struct agentx_session
34  * axc:		struct agentx_context
35  * axr:		struct agentx_region
36  * axi:		struct agentx_index
37  * axo:		struct agentx_object
38  * axg:		struct agentx_get
39  * axv:		struct agentx_varbind
40  * axr:		struct agentx_request
41  * cstate:	current state
42  * dstate:	desired state
43  */
44 
45 enum agentx_index_type {
46 	AXI_TYPE_NEW,
47 	AXI_TYPE_ANY,
48 	AXI_TYPE_VALUE,
49 	AXI_TYPE_DYNAMIC
50 };
51 
52 #define AGENTX_CONTEXT_CTX(axc) (axc->axc_name_default ? NULL : \
53     &(axc->axc_name))
54 
55 struct agentx_agentcaps {
56 	struct agentx_context *axa_axc;
57 	struct ax_oid axa_oid;
58 	struct ax_ostring axa_descr;
59 	enum agentx_cstate axa_cstate;
60 	enum agentx_dstate axa_dstate;
61 	TAILQ_ENTRY(agentx_agentcaps) axa_axc_agentcaps;
62 };
63 
64 struct agentx_region {
65 	struct agentx_context *axr_axc;
66 	struct ax_oid axr_oid;
67 	uint8_t axr_timeout;
68 	uint8_t axr_priority;
69 	enum agentx_cstate axr_cstate;
70 	enum agentx_dstate axr_dstate;
71 	TAILQ_HEAD(, agentx_index) axr_indices;
72 	TAILQ_HEAD(, agentx_object) axr_objects;
73 	TAILQ_ENTRY(agentx_region) axr_axc_regions;
74 };
75 
76 struct agentx_index {
77 	struct agentx_region *axi_axr;
78 	enum agentx_index_type axi_type;
79 	struct ax_varbind axi_vb;
80 	struct agentx_object **axi_object;
81 	size_t axi_objectlen;
82 	size_t axi_objectsize;
83 	enum agentx_cstate axi_cstate;
84 	enum agentx_dstate axi_dstate;
85 	TAILQ_ENTRY(agentx_index) axi_axr_indices;
86 };
87 
88 struct agentx_object {
89 	struct agentx_region *axo_axr;
90 	struct ax_oid axo_oid;
91 	struct agentx_index *axo_index[AGENTX_OID_INDEX_MAX_LEN];
92 	size_t axo_indexlen;
93 	int axo_implied;
94 	uint8_t axo_timeout;
95 	/* Prevent freeing object while in use by get and set requesets */
96 	uint32_t axo_lock;
97 	void (*axo_get)(struct agentx_varbind *);
98 	enum agentx_cstate axo_cstate;
99 	enum agentx_dstate axo_dstate;
100 	RB_ENTRY(agentx_object) axo_axc_objects;
101 	TAILQ_ENTRY(agentx_object) axo_axr_objects;
102 };
103 
104 struct agentx_varbind {
105 	struct agentx_get *axv_axg;
106 	struct agentx_object *axv_axo;
107 	struct agentx_varbind_index {
108 		struct agentx_index *axv_axi;
109 		union ax_data axv_idata;
110 	} axv_index[AGENTX_OID_INDEX_MAX_LEN];
111 	size_t axv_indexlen;
112 	int axv_initialized;
113 	int axv_include;
114 	struct ax_varbind axv_vb;
115 	struct ax_oid axv_start;
116 	struct ax_oid axv_end;
117 	enum ax_pdu_error axv_error;
118 };
119 
120 #define AGENTX_GET_CTX(axg) (axg->axg_context_default ? NULL : \
121     &(axg->axg_context))
122 struct agentx_request {
123 	uint32_t axr_packetid;
124 	int (*axr_cb)(struct ax_pdu *, void *);
125 	void *axr_cookie;
126 	RB_ENTRY(agentx_request) axr_ax_requests;
127 };
128 
129 static void agentx_start(struct agentx *);
130 static void agentx_finalize(struct agentx *, int);
131 static void agentx_wantwritenow(struct agentx *, int);
132 void (*agentx_wantwrite)(struct agentx *, int) =
133     agentx_wantwritenow;
134 static void agentx_reset(struct agentx *);
135 static void agentx_free_finalize(struct agentx *);
136 static int agentx_session_retry(struct agentx_session *);
137 static int agentx_session_start(struct agentx_session *);
138 static int agentx_session_finalize(struct ax_pdu *, void *);
139 static int agentx_session_close(struct agentx_session *,
140     enum ax_close_reason);
141 static int agentx_session_close_finalize(struct ax_pdu *, void *);
142 static void agentx_session_free_finalize(struct agentx_session *);
143 static void agentx_session_reset(struct agentx_session *);
144 static int agentx_context_retry(struct agentx_context *);
145 static void agentx_context_start(struct agentx_context *);
146 static void agentx_context_free_finalize(struct agentx_context *);
147 static void agentx_context_reset(struct agentx_context *);
148 static int agentx_agentcaps_start(struct agentx_agentcaps *);
149 static int agentx_agentcaps_finalize(struct ax_pdu *, void *);
150 static int agentx_agentcaps_close(struct agentx_agentcaps *);
151 static int agentx_agentcaps_close_finalize(struct ax_pdu *, void *);
152 static void agentx_agentcaps_free_finalize(struct agentx_agentcaps *);
153 static void agentx_agentcaps_reset(struct agentx_agentcaps *);
154 static int agentx_region_retry(struct agentx_region *);
155 static int agentx_region_start(struct agentx_region *);
156 static int agentx_region_finalize(struct ax_pdu *, void *);
157 static int agentx_region_close(struct agentx_region *);
158 static int agentx_region_close_finalize(struct ax_pdu *, void *);
159 static void agentx_region_free_finalize(struct agentx_region *);
160 static void agentx_region_reset(struct agentx_region *);
161 static struct agentx_index *agentx_index(struct agentx_region *,
162     struct ax_varbind *, enum agentx_index_type);
163 static int agentx_index_start(struct agentx_index *);
164 static int agentx_index_finalize(struct ax_pdu *, void *);
165 static void agentx_index_free_finalize(struct agentx_index *);
166 static void agentx_index_reset(struct agentx_index *);
167 static int agentx_index_close(struct agentx_index *);
168 static int agentx_index_close_finalize(struct ax_pdu *, void *);
169 static int agentx_object_start(struct agentx_object *);
170 static int agentx_object_finalize(struct ax_pdu *, void *);
171 static int agentx_object_lock(struct agentx_object *);
172 static void agentx_object_unlock(struct agentx_object *);
173 static int agentx_object_close(struct agentx_object *);
174 static int agentx_object_close_finalize(struct ax_pdu *, void *);
175 static void agentx_object_free_finalize(struct agentx_object *);
176 static void agentx_object_reset(struct agentx_object *);
177 static int agentx_object_cmp(struct agentx_object *,
178     struct agentx_object *);
179 static void agentx_get_start(struct agentx_context *,
180     struct ax_pdu *);
181 static void agentx_get_finalize(struct agentx_get *);
182 static void agentx_get_free(struct agentx_get *);
183 static void agentx_varbind_start(struct agentx_varbind *);
184 static void agentx_varbind_finalize(struct agentx_varbind *);
185 static void agentx_varbind_nosuchobject(struct agentx_varbind *);
186 static void agentx_varbind_nosuchinstance(struct agentx_varbind *);
187 static void agentx_varbind_endofmibview(struct agentx_varbind *);
188 static void agentx_varbind_error_type(struct agentx_varbind *,
189     enum ax_pdu_error, int);
190 static int agentx_request(struct agentx *, uint32_t,
191     int (*)(struct ax_pdu *, void *), void *);
192 static int agentx_request_cmp(struct agentx_request *,
193     struct agentx_request *);
194 static int agentx_strcat(char **, const char *);
195 static int agentx_oidfill(struct ax_oid *, const uint32_t[], size_t,
196     const char **);
197 
RB_PROTOTYPE_STATIC(ax_requests,agentx_request,axr_ax_requests,agentx_request_cmp)198 RB_PROTOTYPE_STATIC(ax_requests, agentx_request, axr_ax_requests,
199     agentx_request_cmp)
200 RB_PROTOTYPE_STATIC(axc_objects, agentx_object, axo_axc_objects,
201     agentx_object_cmp)
202 
203 struct agentx *
204 agentx(void (*nofd)(struct agentx *, void *, int), void *cookie)
205 {
206 	struct agentx *ax;
207 
208 	if ((ax = calloc(1, sizeof(*ax))) == NULL)
209 		return NULL;
210 
211 	ax->ax_nofd = nofd;
212 	ax->ax_cookie = cookie;
213 	ax->ax_fd = -1;
214 	ax->ax_cstate = AX_CSTATE_CLOSE;
215 	ax->ax_dstate = AX_DSTATE_OPEN;
216 	TAILQ_INIT(&(ax->ax_sessions));
217 	TAILQ_INIT(&(ax->ax_getreqs));
218 	RB_INIT(&(ax->ax_requests));
219 
220 	agentx_start(ax);
221 
222 	return ax;
223 }
224 
225 /*
226  * agentx_finalize is not a suitable name for a public API,
227  * but use it internally for consistency
228  */
229 void
agentx_connect(struct agentx * ax,int fd)230 agentx_connect(struct agentx *ax, int fd)
231 {
232 	agentx_finalize(ax, fd);
233 }
234 
235 void
agentx_retry(struct agentx * ax)236 agentx_retry(struct agentx *ax)
237 {
238 	struct agentx_session *axs;
239 
240 	if (ax->ax_fd == -1)
241 		return;
242 
243 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
244 		if (axs->axs_cstate == AX_CSTATE_OPEN) {
245 			if (agentx_session_retry(axs) == -1)
246 				return;
247 		} else if (axs->axs_cstate == AX_CSTATE_CLOSE) {
248 			if (agentx_session_start(axs) == -1)
249 				return;
250 		}
251 	}
252 }
253 
254 static void
agentx_start(struct agentx * ax)255 agentx_start(struct agentx *ax)
256 {
257 #ifdef AX_DEBUG
258 	if (ax->ax_cstate != AX_CSTATE_CLOSE ||
259 	    ax->ax_dstate != AX_DSTATE_OPEN)
260 		agentx_log_ax_fatalx(ax, "%s: unexpected connect", __func__);
261 #endif
262 	ax->ax_cstate = AX_CSTATE_WAITOPEN;
263 	ax->ax_nofd(ax, ax->ax_cookie, 0);
264 }
265 
266 static void
agentx_finalize(struct agentx * ax,int fd)267 agentx_finalize(struct agentx *ax, int fd)
268 {
269 	struct agentx_session *axs;
270 
271 	if (ax->ax_cstate != AX_CSTATE_WAITOPEN) {
272 #ifdef AX_DEBUG
273 		agentx_log_ax_fatalx(ax, "%s: agentx unexpected connect",
274 		    __func__);
275 #else
276 		agentx_log_ax_warnx(ax,
277 		    "%s: agentx unexpected connect: ignoring", __func__);
278 		return;
279 #endif
280 	}
281 	if ((ax->ax_ax = ax_new(fd)) == NULL) {
282 		agentx_log_ax_warn(ax, "failed to initialize");
283 		close(fd);
284 		agentx_reset(ax);
285 		return;
286 	}
287 
288 	agentx_log_ax_info(ax, "new connection: %d", fd);
289 
290 	ax->ax_fd = fd;
291 	ax->ax_cstate = AX_CSTATE_OPEN;
292 
293 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
294 		if (agentx_session_start(axs) == -1)
295 			break;
296 	}
297 }
298 
299 static void
agentx_wantwritenow(struct agentx * ax,int fd)300 agentx_wantwritenow(struct agentx *ax, int fd)
301 {
302 	agentx_write(ax);
303 }
304 
305 static void
agentx_reset(struct agentx * ax)306 agentx_reset(struct agentx *ax)
307 {
308 	struct agentx_session *axs, *taxs;
309 	struct agentx_request *axr;
310 	struct agentx_get *axg;
311 	int axfree = ax->ax_free;
312 
313 	ax_free(ax->ax_ax);
314 	ax->ax_ax = NULL;
315 	ax->ax_fd = -1;
316 	ax->ax_free = 1;
317 
318 	ax->ax_cstate = AX_CSTATE_CLOSE;
319 
320 	while ((axr = RB_MIN(ax_requests, &(ax->ax_requests))) != NULL) {
321 		RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
322 		free(axr);
323 	}
324 	TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
325 		agentx_session_reset(axs);
326 	while (!TAILQ_EMPTY(&(ax->ax_getreqs))) {
327 		axg = TAILQ_FIRST(&(ax->ax_getreqs));
328 		axg->axg_axc = NULL;
329 		TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
330 	}
331 
332 	if (ax->ax_dstate == AX_DSTATE_OPEN)
333 		agentx_start(ax);
334 
335 	if (!axfree)
336 		agentx_free_finalize(ax);
337 }
338 
339 void
agentx_free(struct agentx * ax)340 agentx_free(struct agentx *ax)
341 {
342 	struct agentx_session *axs, *taxs;
343 	int axfree;
344 
345 	if (ax == NULL)
346 		return;
347 
348 	axfree = ax->ax_free;
349 	ax->ax_free = 1;
350 
351 	/* Malloc throws abort on invalid pointers as well */
352 	if (ax->ax_dstate == AX_DSTATE_CLOSE)
353 		agentx_log_ax_fatalx(ax, "%s: double free", __func__);
354 	ax->ax_dstate = AX_DSTATE_CLOSE;
355 
356 	TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs) {
357 		if (axs->axs_dstate != AX_DSTATE_CLOSE)
358 			agentx_session_free(axs);
359 	}
360 	if (!axfree)
361 		agentx_free_finalize(ax);
362 }
363 
364 static void
agentx_free_finalize(struct agentx * ax)365 agentx_free_finalize(struct agentx *ax)
366 {
367 	struct agentx_session *axs, *taxs;
368 
369 	ax->ax_free = 0;
370 
371 	TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
372 		agentx_session_free_finalize(axs);
373 
374 	if (!TAILQ_EMPTY(&(ax->ax_sessions)) ||
375 	    !RB_EMPTY(&(ax->ax_requests)) ||
376 	    ax->ax_dstate != AX_DSTATE_CLOSE)
377 		return;
378 
379 	ax_free(ax->ax_ax);
380 	ax->ax_nofd(ax, ax->ax_cookie, 1);
381 	free(ax);
382 }
383 
384 struct agentx_session *
agentx_session(struct agentx * ax,uint32_t oid[],size_t oidlen,const char * descr,uint8_t timeout)385 agentx_session(struct agentx *ax, uint32_t oid[],
386     size_t oidlen, const char *descr, uint8_t timeout)
387 {
388 	struct agentx_session *axs;
389 	const char *errstr;
390 
391 	if ((axs = calloc(1, sizeof(*axs))) == NULL)
392 		return NULL;
393 
394 	axs->axs_ax = ax;
395 	axs->axs_timeout = timeout;
396 	/* RFC 2741 section 6.2.1: may send a null Object Identifier */
397 	if (oidlen == 0)
398 		axs->axs_oid.aoi_idlen = oidlen;
399 	else {
400 		if (agentx_oidfill((&axs->axs_oid), oid, oidlen,
401 		    &errstr) == -1) {
402 #ifdef AX_DEBUG
403 			agentx_log_ax_fatalx(ax, "%s: %s", __func__, errstr);
404 #else
405 			return NULL;
406 #endif
407 		}
408 	}
409 	axs->axs_descr.aos_string = (unsigned char *)strdup(descr);
410 	if (axs->axs_descr.aos_string == NULL) {
411 		free(axs);
412 		return NULL;
413 	}
414 	axs->axs_descr.aos_slen = strlen(descr);
415 	axs->axs_cstate = AX_CSTATE_CLOSE;
416 	axs->axs_dstate = AX_DSTATE_OPEN;
417 	TAILQ_INIT(&(axs->axs_contexts));
418 	TAILQ_INSERT_HEAD(&(ax->ax_sessions), axs, axs_ax_sessions);
419 
420 	if (ax->ax_cstate == AX_CSTATE_OPEN)
421 		(void) agentx_session_start(axs);
422 
423 	return axs;
424 }
425 
426 static int
agentx_session_retry(struct agentx_session * axs)427 agentx_session_retry(struct agentx_session *axs)
428 {
429 	struct agentx_context *axc;
430 
431 #ifdef AX_DEBUG
432 	if (axs->axs_cstate != AX_CSTATE_OPEN)
433 		agentx_log_axs_fatalx(axs, "%s: unexpected retry", __func__);
434 #endif
435 
436 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts) {
437 		if (axc->axc_cstate == AX_CSTATE_OPEN) {
438 			if (agentx_context_retry(axc) == -1)
439 				return -1;
440 		} else if (axc->axc_cstate == AX_CSTATE_CLOSE)
441 			agentx_context_start(axc);
442 	}
443 	return 0;
444 }
445 
446 static int
agentx_session_start(struct agentx_session * axs)447 agentx_session_start(struct agentx_session *axs)
448 {
449 	struct agentx *ax = axs->axs_ax;
450 	uint32_t packetid;
451 
452 #ifdef AX_DEBUG
453 	if (ax->ax_cstate != AX_CSTATE_OPEN ||
454 	    axs->axs_cstate != AX_CSTATE_CLOSE ||
455 	    axs->axs_dstate != AX_DSTATE_OPEN)
456 		agentx_log_ax_fatalx(ax, "%s: unexpected session open",
457 		    __func__);
458 #endif
459 	packetid = ax_open(ax->ax_ax, axs->axs_timeout, &(axs->axs_oid),
460 	    &(axs->axs_descr));
461 	if (packetid == 0) {
462 		agentx_log_ax_warn(ax, "couldn't generate %s",
463 		    ax_pdutype2string(AX_PDU_TYPE_OPEN));
464 		agentx_reset(ax);
465 		return -1;
466 	}
467 	axs->axs_packetid = packetid;
468 	agentx_log_ax_info(ax, "opening session");
469 	axs->axs_cstate = AX_CSTATE_WAITOPEN;
470 	return agentx_request(ax, packetid, agentx_session_finalize, axs);
471 }
472 
473 static int
agentx_session_finalize(struct ax_pdu * pdu,void * cookie)474 agentx_session_finalize(struct ax_pdu *pdu, void *cookie)
475 {
476 	struct agentx_session *axs = cookie;
477 	struct agentx *ax = axs->axs_ax;
478 	struct agentx_context *axc;
479 
480 #ifdef AX_DEBUG
481 	if (axs->axs_cstate != AX_CSTATE_WAITOPEN)
482 		agentx_log_ax_fatalx(ax, "%s: not expecting new session",
483 		    __func__);
484 #endif
485 
486 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
487 		agentx_log_ax_warnx(ax, "failed to open session: %s",
488 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
489 		axs->axs_cstate = AX_CSTATE_CLOSE;
490 		return -1;
491 	}
492 
493 	axs->axs_id = pdu->ap_header.aph_sessionid;
494 	axs->axs_cstate = AX_CSTATE_OPEN;
495 
496 	if (axs->axs_dstate == AX_DSTATE_CLOSE) {
497 		agentx_session_close(axs, AX_CLOSE_SHUTDOWN);
498 		return 0;
499 	}
500 
501 	agentx_log_axs_info(axs, "open");
502 
503 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts)
504 		agentx_context_start(axc);
505 	return 0;
506 }
507 
508 static int
agentx_session_close(struct agentx_session * axs,enum ax_close_reason reason)509 agentx_session_close(struct agentx_session *axs,
510     enum ax_close_reason reason)
511 {
512 	struct agentx *ax = axs->axs_ax;
513 	uint32_t packetid;
514 
515 #ifdef AX_DEBUG
516 	if (axs->axs_cstate != AX_CSTATE_OPEN)
517 		agentx_log_ax_fatalx(ax, "%s: unexpected session close",
518 		    __func__);
519 #endif
520 	if ((packetid = ax_close(ax->ax_ax, axs->axs_id, reason)) == 0) {
521 		agentx_log_axs_warn(axs, "couldn't generate %s",
522 		    ax_pdutype2string(AX_PDU_TYPE_CLOSE));
523 		agentx_reset(ax);
524 		return -1;
525 	}
526 
527 	agentx_log_axs_info(axs, "closing session: %s",
528 	    ax_closereason2string(reason));
529 
530 	axs->axs_cstate = AX_CSTATE_WAITCLOSE;
531 	return agentx_request(ax, packetid, agentx_session_close_finalize,
532 	    axs);
533 }
534 
535 static int
agentx_session_close_finalize(struct ax_pdu * pdu,void * cookie)536 agentx_session_close_finalize(struct ax_pdu *pdu, void *cookie)
537 {
538 	struct agentx_session *axs = cookie;
539 	struct agentx *ax = axs->axs_ax;
540 	struct agentx_context *axc, *taxc;
541 	int axfree = ax->ax_free;
542 
543 #ifdef AX_DEBUG
544 	if (axs->axs_cstate != AX_CSTATE_WAITCLOSE)
545 		agentx_log_axs_fatalx(axs, "%s: not expecting session close",
546 		    __func__);
547 #endif
548 
549 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
550 		agentx_log_axs_warnx(axs, "failed to close session: %s",
551 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
552 		agentx_reset(ax);
553 		return -1;
554 	}
555 
556 	axs->axs_cstate = AX_CSTATE_CLOSE;
557 	ax->ax_free = 1;
558 
559 	agentx_log_axs_info(axs, "closed");
560 
561 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
562 		agentx_context_reset(axc);
563 
564 	if (ax->ax_cstate == AX_CSTATE_OPEN &&
565 	    axs->axs_dstate == AX_DSTATE_OPEN)
566 		agentx_session_start(axs);
567 	if (!axfree)
568 		agentx_free_finalize(ax);
569 
570 	return 0;
571 }
572 
573 void
agentx_session_free(struct agentx_session * axs)574 agentx_session_free(struct agentx_session *axs)
575 {
576 	struct agentx_context *axc, *taxc;
577 	struct agentx *ax;
578 	int axfree;
579 
580 	if (axs == NULL)
581 		return;
582 
583 	ax = axs->axs_ax;
584 	axfree = ax->ax_free;
585 	ax->ax_free = 1;
586 
587 	if (axs->axs_dstate == AX_DSTATE_CLOSE)
588 		agentx_log_axs_fatalx(axs, "%s: double free", __func__);
589 
590 	axs->axs_dstate = AX_DSTATE_CLOSE;
591 
592 	if (axs->axs_cstate == AX_CSTATE_OPEN)
593 		(void) agentx_session_close(axs, AX_CLOSE_SHUTDOWN);
594 
595 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc) {
596 		if (axc->axc_dstate != AX_DSTATE_CLOSE)
597 			agentx_context_free(axc);
598 	}
599 
600 	if (!axfree)
601 		agentx_free_finalize(ax);
602 }
603 
604 static void
agentx_session_free_finalize(struct agentx_session * axs)605 agentx_session_free_finalize(struct agentx_session *axs)
606 {
607 	struct agentx *ax = axs->axs_ax;
608 	struct agentx_context *axc, *taxc;
609 
610 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
611 		agentx_context_free_finalize(axc);
612 
613 	if (!TAILQ_EMPTY(&(axs->axs_contexts)) ||
614 	    axs->axs_cstate != AX_CSTATE_CLOSE ||
615 	    axs->axs_dstate != AX_DSTATE_CLOSE)
616 		return;
617 
618 	TAILQ_REMOVE(&(ax->ax_sessions), axs, axs_ax_sessions);
619 	free(axs->axs_descr.aos_string);
620 	free(axs);
621 }
622 
623 static void
agentx_session_reset(struct agentx_session * axs)624 agentx_session_reset(struct agentx_session *axs)
625 {
626 	struct agentx_context *axc, *taxc;
627 	struct agentx *ax = axs->axs_ax;
628 	int axfree = ax->ax_free;
629 
630 	ax->ax_free = 1;
631 
632 	axs->axs_cstate = AX_CSTATE_CLOSE;
633 
634 	TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
635 		agentx_context_reset(axc);
636 
637 	if (!axfree)
638 		agentx_free_finalize(ax);
639 }
640 
641 struct agentx_context *
agentx_context(struct agentx_session * axs,const char * name)642 agentx_context(struct agentx_session *axs, const char *name)
643 {
644 	struct agentx_context *axc;
645 
646 	if (axs->axs_dstate == AX_DSTATE_CLOSE)
647 		agentx_log_axs_fatalx(axs, "%s: use after free", __func__);
648 
649 	if ((axc = calloc(1, sizeof(*axc))) == NULL)
650 		return NULL;
651 
652 	axc->axc_axs = axs;
653 	axc->axc_name_default = (name == NULL);
654 	if (name != NULL) {
655 		axc->axc_name.aos_string = (unsigned char *)strdup(name);
656 		if (axc->axc_name.aos_string == NULL) {
657 			free(axc);
658 			return NULL;
659 		}
660 		axc->axc_name.aos_slen = strlen(name);
661 	}
662 	axc->axc_cstate = axs->axs_cstate == AX_CSTATE_OPEN ?
663 	    AX_CSTATE_OPEN : AX_CSTATE_CLOSE;
664 	axc->axc_dstate = AX_DSTATE_OPEN;
665 	TAILQ_INIT(&(axc->axc_agentcaps));
666 	TAILQ_INIT(&(axc->axc_regions));
667 
668 	TAILQ_INSERT_HEAD(&(axs->axs_contexts), axc, axc_axs_contexts);
669 
670 	return axc;
671 }
672 
673 static int
agentx_context_retry(struct agentx_context * axc)674 agentx_context_retry(struct agentx_context *axc)
675 {
676 	struct agentx_agentcaps *axa;
677 	struct agentx_region *axr;
678 
679 #ifdef AX_DEBUG
680 	if (axc->axc_cstate != AX_CSTATE_OPEN)
681 		agentx_log_axc_fatalx(axc, "%s: unexpected retry", __func__);
682 #endif
683 
684 	TAILQ_FOREACH(axa, &(axc->axc_agentcaps), axa_axc_agentcaps) {
685 		if (axa->axa_cstate == AX_CSTATE_CLOSE) {
686 			if (agentx_agentcaps_start(axa) == -1)
687 				return -1;
688 		}
689 	}
690 	TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
691 		if (axr->axr_cstate == AX_CSTATE_OPEN) {
692 			if (agentx_region_retry(axr) == -1)
693 				return -1;
694 		} else if (axr->axr_cstate == AX_CSTATE_CLOSE) {
695 			if (agentx_region_start(axr) == -1)
696 				return -1;
697 		}
698 	}
699 	return 0;
700 }
701 
702 
703 static void
agentx_context_start(struct agentx_context * axc)704 agentx_context_start(struct agentx_context *axc)
705 {
706 	struct agentx_agentcaps *axa;
707 	struct agentx_region *axr;
708 
709 #ifdef AX_DEBUG
710 	if (axc->axc_cstate != AX_CSTATE_CLOSE)
711 		agentx_log_axc_fatalx(axc, "%s: unexpected context start",
712 		    __func__);
713 #endif
714 	axc->axc_cstate = AX_CSTATE_OPEN;
715 
716 	TAILQ_FOREACH(axa, &(axc->axc_agentcaps), axa_axc_agentcaps) {
717 		if (agentx_agentcaps_start(axa) == -1)
718 			return;
719 	}
720 	TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
721 		if (agentx_region_start(axr) == -1)
722 			return;
723 	}
724 }
725 
726 uint32_t
agentx_context_uptime(struct agentx_context * axc)727 agentx_context_uptime(struct agentx_context *axc)
728 {
729 	struct timespec cur, res;
730 
731 	if (axc->axc_sysuptimespec.tv_sec == 0 &&
732 	    axc->axc_sysuptimespec.tv_nsec == 0)
733 		return 0;
734 
735 	(void) clock_gettime(CLOCK_MONOTONIC, &cur);
736 
737 	timespecsub(&cur, &(axc->axc_sysuptimespec), &res);
738 
739 	return axc->axc_sysuptime +
740 	    (uint32_t) ((res.tv_sec * 100) + (res.tv_nsec / 10000000));
741 }
742 
743 struct agentx_object *
agentx_context_object_find(struct agentx_context * axc,const uint32_t oid[],size_t oidlen,int active,int instance)744 agentx_context_object_find(struct agentx_context *axc,
745     const uint32_t oid[], size_t oidlen, int active, int instance)
746 {
747 	struct agentx_object *axo, axo_search;
748 	const char *errstr;
749 
750 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
751 		if (oidlen > AGENTX_OID_MIN_LEN) {
752 #ifdef AX_DEBUG
753 			agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
754 #else
755 			agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
756 			return NULL;
757 		}
758 #endif
759 		if (oidlen == 1)
760 			axo_search.axo_oid.aoi_id[0] = oid[0];
761 		axo_search.axo_oid.aoi_idlen = oidlen;
762 	}
763 
764 	axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
765 	while (axo == NULL && !instance && axo_search.axo_oid.aoi_idlen > 0) {
766 		axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
767 		axo_search.axo_oid.aoi_idlen--;
768 	}
769 	if (active && axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
770 		return NULL;
771 	return axo;
772 }
773 
774 struct agentx_object *
775 agentx_context_object_nfind(struct agentx_context *axc,
776     const uint32_t oid[], size_t oidlen, int active, int inclusive)
777 {
778 	struct agentx_object *axo, axo_search;
779 	const char *errstr;
780 
781 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
782 		if (oidlen > AGENTX_OID_MIN_LEN) {
783 #ifdef AX_DEBUG
784 			agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
785 #else
786 			agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
787 			return NULL;
788 #endif
789 		}
790 		if (oidlen == 1)
791 			axo_search.axo_oid.aoi_id[0] = oid[0];
792 		axo_search.axo_oid.aoi_idlen = oidlen;
793 	}
794 
795 	axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
796 	if (!inclusive && axo != NULL &&
797 	    ax_oid_cmp(&(axo->axo_oid), &(axo_search.axo_oid)) <= 0) {
798 		axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
799 	}
800 
801 	while (active && axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
802 		axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
803 	return axo;
804 }
805 
806 void
807 agentx_context_free(struct agentx_context *axc)
808 {
809 	struct agentx_agentcaps *axa, *taxa;
810 	struct agentx_region *axr, *taxr;
811 
812 	if (axc == NULL)
813 		return;
814 
815 #ifdef AX_DEBUG
816 	if (axc->axc_dstate == AX_DSTATE_CLOSE)
817 		agentx_log_axc_fatalx(axc, "%s: double free", __func__);
818 #endif
819 	axc->axc_dstate = AX_DSTATE_CLOSE;
820 
821 	TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps,
822 	    taxa) {
823 		if (axa->axa_dstate != AX_DSTATE_CLOSE)
824 			agentx_agentcaps_free(axa);
825 	}
826 	TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr) {
827 		if (axr->axr_dstate != AX_DSTATE_CLOSE)
828 			agentx_region_free(axr);
829 	}
830 }
831 
832 static void
833 agentx_context_free_finalize(struct agentx_context *axc)
834 {
835 	struct agentx_session *axs = axc->axc_axs;
836 	struct agentx_region *axr, *taxr;
837 	struct agentx_agentcaps *axa, *taxa;
838 
839 	TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, taxa)
840 		agentx_agentcaps_free_finalize(axa);
841 	TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr)
842 		agentx_region_free_finalize(axr);
843 
844 	if (!TAILQ_EMPTY(&(axc->axc_regions)) ||
845 	    !TAILQ_EMPTY(&(axc->axc_agentcaps)) ||
846 	    axc->axc_cstate != AX_CSTATE_CLOSE ||
847 	    axc->axc_dstate != AX_DSTATE_CLOSE)
848 		return;
849 
850 	TAILQ_REMOVE(&(axs->axs_contexts), axc, axc_axs_contexts);
851 	free(axc->axc_name.aos_string);
852 	free(axc);
853 }
854 
855 static void
856 agentx_context_reset(struct agentx_context *axc)
857 {
858 	struct agentx_agentcaps *axa, *taxa;
859 	struct agentx_region *axr, *taxr;
860 	struct agentx *ax = axc->axc_axs->axs_ax;
861 	int axfree = ax->ax_free;
862 
863 	ax->ax_free = 1;
864 
865 	axc->axc_cstate = AX_CSTATE_CLOSE;
866 	axc->axc_sysuptimespec.tv_sec = 0;
867 	axc->axc_sysuptimespec.tv_nsec = 0;
868 
869 	TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, taxa)
870 		agentx_agentcaps_reset(axa);
871 	TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr)
872 		agentx_region_reset(axr);
873 
874 	if (!axfree)
875 		agentx_free_finalize(ax);
876 }
877 
878 struct agentx_agentcaps *
879 agentx_agentcaps(struct agentx_context *axc, uint32_t oid[],
880     size_t oidlen, const char *descr)
881 {
882 	struct agentx_agentcaps *axa;
883 	const char *errstr;
884 
885 	if (axc->axc_dstate == AX_DSTATE_CLOSE)
886 		agentx_log_axc_fatalx(axc, "%s: use after free", __func__);
887 
888 	if ((axa = calloc(1, sizeof(*axa))) == NULL)
889 		return NULL;
890 
891 	axa->axa_axc = axc;
892 	if (agentx_oidfill(&(axa->axa_oid), oid, oidlen, &errstr) == -1) {
893 #ifdef AX_DEBUG
894 		agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
895 #else
896 		agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
897 		return NULL;
898 #endif
899 	}
900 	axa->axa_descr.aos_string = (unsigned char *)strdup(descr);
901 	if (axa->axa_descr.aos_string == NULL) {
902 		free(axa);
903 		return NULL;
904 	}
905 	axa->axa_descr.aos_slen = strlen(descr);
906 	axa->axa_cstate = AX_CSTATE_CLOSE;
907 	axa->axa_dstate = AX_DSTATE_OPEN;
908 
909 	TAILQ_INSERT_TAIL(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
910 
911 	if (axc->axc_cstate == AX_CSTATE_OPEN)
912 		agentx_agentcaps_start(axa);
913 
914 	return axa;
915 }
916 
917 static int
918 agentx_agentcaps_start(struct agentx_agentcaps *axa)
919 {
920 	struct agentx_context *axc = axa->axa_axc;
921 	struct agentx_session *axs = axc->axc_axs;
922 	struct agentx *ax = axs->axs_ax;
923 	uint32_t packetid;
924 
925 #ifdef AX_DEBUG
926 	if (axc->axc_cstate != AX_CSTATE_OPEN ||
927 	    axa->axa_cstate != AX_CSTATE_CLOSE ||
928 	    axa->axa_dstate != AX_DSTATE_OPEN)
929 		agentx_log_axc_fatalx(axc,
930 		    "%s: unexpected region registration", __func__);
931 #endif
932 
933 	packetid = ax_addagentcaps(ax->ax_ax, axs->axs_id,
934 	    AGENTX_CONTEXT_CTX(axc), &(axa->axa_oid), &(axa->axa_descr));
935 	if (packetid == 0) {
936 		agentx_log_axc_warn(axc, "couldn't generate %s",
937 		    ax_pdutype2string(AX_PDU_TYPE_ADDAGENTCAPS));
938 		agentx_reset(ax);
939 		return -1;
940 	}
941 	agentx_log_axc_info(axc, "agentcaps %s: opening",
942 	    ax_oid2string(&(axa->axa_oid)));
943 	axa->axa_cstate = AX_CSTATE_WAITOPEN;
944 	return agentx_request(ax, packetid, agentx_agentcaps_finalize,
945 	    axa);
946 }
947 
948 static int
949 agentx_agentcaps_finalize(struct ax_pdu *pdu, void *cookie)
950 {
951 	struct agentx_agentcaps *axa = cookie;
952 	struct agentx_context *axc = axa->axa_axc;
953 
954 #ifdef AX_DEBUG
955 	if (axa->axa_cstate != AX_CSTATE_WAITOPEN)
956 		agentx_log_axc_fatalx(axc,
957 		    "%s: not expecting agentcaps open", __func__);
958 #endif
959 
960 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
961 		/* Agentcaps failing is nothing too serious */
962 		agentx_log_axc_warn(axc, "agentcaps %s: %s",
963 		    ax_oid2string(&(axa->axa_oid)),
964 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
965 		axa->axa_cstate = AX_CSTATE_CLOSE;
966 		return 0;
967 	}
968 
969 	axa->axa_cstate = AX_CSTATE_OPEN;
970 
971 	agentx_log_axc_info(axc, "agentcaps %s: open",
972 	    ax_oid2string(&(axa->axa_oid)));
973 
974 	if (axa->axa_dstate == AX_DSTATE_CLOSE)
975 		agentx_agentcaps_close(axa);
976 
977 	return 0;
978 }
979 
980 static int
981 agentx_agentcaps_close(struct agentx_agentcaps *axa)
982 {
983 	struct agentx_context *axc = axa->axa_axc;
984 	struct agentx_session *axs = axc->axc_axs;
985 	struct agentx *ax = axs->axs_ax;
986 	uint32_t packetid;
987 
988 #ifdef AX_DEBUG
989 	if (axa->axa_cstate != AX_CSTATE_OPEN)
990 		agentx_log_axc_fatalx(axc, "%s: unexpected agentcaps close",
991 		    __func__);
992 #endif
993 
994 	axa->axa_cstate = AX_CSTATE_WAITCLOSE;
995 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
996 		return 0;
997 
998 	packetid = ax_removeagentcaps(ax->ax_ax, axs->axs_id,
999 	    AGENTX_CONTEXT_CTX(axc), &(axa->axa_oid));
1000 	if (packetid == 0) {
1001 		agentx_log_axc_warn(axc, "couldn't generate %s",
1002 		    ax_pdutype2string(AX_PDU_TYPE_REMOVEAGENTCAPS));
1003 		agentx_reset(ax);
1004 		return -1;
1005 	}
1006 	agentx_log_axc_info(axc, "agentcaps %s: closing",
1007 	    ax_oid2string(&(axa->axa_oid)));
1008 	return agentx_request(ax, packetid,
1009 	    agentx_agentcaps_close_finalize, axa);
1010 }
1011 
1012 static int
1013 agentx_agentcaps_close_finalize(struct ax_pdu *pdu, void *cookie)
1014 {
1015 	struct agentx_agentcaps *axa = cookie;
1016 	struct agentx_context *axc = axa->axa_axc;
1017 	struct agentx_session *axs = axc->axc_axs;
1018 	struct agentx *ax = axs->axs_ax;
1019 	int axfree = ax->ax_free;
1020 
1021 #ifdef AX_DEBUG
1022 	if (axa->axa_cstate != AX_CSTATE_WAITCLOSE)
1023 		agentx_log_axc_fatalx(axc, "%s: unexpected agentcaps close",
1024 		    __func__);
1025 #endif
1026 
1027 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
1028 		agentx_log_axc_warnx(axc, "agentcaps %s: %s",
1029 		    ax_oid2string(&(axa->axa_oid)),
1030 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
1031 		agentx_reset(ax);
1032 		return -1;
1033 	}
1034 
1035 	axa->axa_cstate = AX_CSTATE_CLOSE;
1036 	ax->ax_free = 1;
1037 
1038 	agentx_log_axc_info(axc, "agentcaps %s: closed",
1039 	    ax_oid2string(&(axa->axa_oid)));
1040 
1041 	if (axc->axc_cstate == AX_CSTATE_OPEN &&
1042 	    axa->axa_dstate == AX_DSTATE_OPEN)
1043 		agentx_agentcaps_start(axa);
1044 
1045 	if (!axfree)
1046 		agentx_free_finalize(ax);
1047 	return 0;
1048 }
1049 
1050 void
1051 agentx_agentcaps_free(struct agentx_agentcaps *axa)
1052 {
1053 	struct agentx *ax = axa->axa_axc->axc_axs->axs_ax;
1054 	int axfree;
1055 
1056 	if (axa == NULL)
1057 		return;
1058 
1059 	axfree = ax->ax_free;
1060 	ax->ax_free = 1;
1061 
1062 	if (axa->axa_dstate == AX_DSTATE_CLOSE)
1063 		agentx_log_axc_fatalx(axa->axa_axc, "%s: double free",
1064 		    __func__);
1065 
1066 	axa->axa_dstate = AX_DSTATE_CLOSE;
1067 
1068 	if (axa->axa_cstate == AX_CSTATE_OPEN)
1069 		agentx_agentcaps_close(axa);
1070 
1071 	if (!axfree)
1072 		agentx_free_finalize(ax);
1073 }
1074 
1075 static void
1076 agentx_agentcaps_free_finalize(struct agentx_agentcaps *axa)
1077 {
1078 	struct agentx_context *axc = axa->axa_axc;
1079 
1080 	if (axa->axa_dstate != AX_DSTATE_CLOSE ||
1081 	    axa->axa_cstate != AX_CSTATE_CLOSE)
1082 		return;
1083 
1084 	TAILQ_REMOVE(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
1085 	free(axa->axa_descr.aos_string);
1086 	free(axa);
1087 }
1088 
1089 static void
1090 agentx_agentcaps_reset(struct agentx_agentcaps *axa)
1091 {
1092 	struct agentx *ax = axa->axa_axc->axc_axs->axs_ax;
1093 
1094 	axa->axa_cstate = AX_CSTATE_CLOSE;
1095 
1096 	if (!ax->ax_free)
1097 		agentx_free_finalize(ax);
1098 }
1099 
1100 struct agentx_region *
1101 agentx_region(struct agentx_context *axc, uint32_t oid[],
1102     size_t oidlen, uint8_t timeout)
1103 {
1104 	struct agentx_region *axr;
1105 	struct ax_oid tmpoid;
1106 	const char *errstr;
1107 
1108 	if (axc->axc_dstate == AX_DSTATE_CLOSE)
1109 		agentx_log_axc_fatalx(axc, "%s: use after free", __func__);
1110 
1111 	if (agentx_oidfill(&tmpoid, oid, oidlen, &errstr) == -1) {
1112 #ifdef AX_DEBUG
1113 		agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
1114 #else
1115 		return NULL;
1116 #endif
1117 
1118 	}
1119 	TAILQ_FOREACH(axr, &(axc->axc_regions), axr_axc_regions) {
1120 		if (ax_oid_cmp(&(axr->axr_oid), &tmpoid) == 0) {
1121 #ifdef AX_DEBUG
1122 			agentx_log_axc_fatalx(axc,
1123 			    "%s: duplicate region registration", __func__);
1124 #else
1125 			errno = EINVAL;
1126 			return NULL;
1127 #endif
1128 		}
1129 	}
1130 
1131 	if ((axr = calloc(1, sizeof(*axr))) == NULL)
1132 		return NULL;
1133 
1134 	axr->axr_axc = axc;
1135 	axr->axr_timeout = timeout;
1136 	axr->axr_priority = AX_PRIORITY_DEFAULT;
1137 	bcopy(&tmpoid, &(axr->axr_oid), sizeof(axr->axr_oid));
1138 	axr->axr_cstate = AX_CSTATE_CLOSE;
1139 	axr->axr_dstate = AX_DSTATE_OPEN;
1140 	TAILQ_INIT(&(axr->axr_indices));
1141 	TAILQ_INIT(&(axr->axr_objects));
1142 
1143 	TAILQ_INSERT_HEAD(&(axc->axc_regions), axr, axr_axc_regions);
1144 
1145 	if (axc->axc_cstate == AX_CSTATE_OPEN)
1146 		(void) agentx_region_start(axr);
1147 
1148 	return axr;
1149 }
1150 
1151 static int
1152 agentx_region_retry(struct agentx_region *axr)
1153 {
1154 	struct agentx_index *axi;
1155 	struct agentx_object *axo;
1156 
1157 #ifdef AX_DEBUG
1158 	if (axr->axr_cstate != AX_CSTATE_OPEN)
1159 		agentx_log_axc_fatalx(axr->axr_axc,
1160 		    "%s: unexpected retry", __func__);
1161 #endif
1162 
1163 	TAILQ_FOREACH(axi, &(axr->axr_indices), axi_axr_indices) {
1164 		if (axi->axi_cstate == AX_CSTATE_CLOSE) {
1165 			if (agentx_index_start(axi) == -1)
1166 				return -1;
1167 		}
1168 	}
1169 	TAILQ_FOREACH(axo, &(axr->axr_objects), axo_axr_objects) {
1170 		if (axo->axo_cstate == AX_CSTATE_CLOSE) {
1171 			if (agentx_object_start(axo) == -1)
1172 				return -1;
1173 		}
1174 	}
1175 	return 0;
1176 }
1177 
1178 static int
1179 agentx_region_start(struct agentx_region *axr)
1180 {
1181 	struct agentx_context *axc = axr->axr_axc;
1182 	struct agentx_session *axs = axc->axc_axs;
1183 	struct agentx *ax = axs->axs_ax;
1184 	uint32_t packetid;
1185 
1186 #ifdef AX_DEBUG
1187 	if (axc->axc_cstate != AX_CSTATE_OPEN ||
1188 	    axr->axr_cstate != AX_CSTATE_CLOSE ||
1189 	    axr->axr_dstate != AX_DSTATE_OPEN)
1190 		agentx_log_axc_fatalx(axc,
1191 		    "%s: unexpected region registration", __func__);
1192 #endif
1193 
1194 	packetid = ax_register(ax->ax_ax, 0, axs->axs_id,
1195 	    AGENTX_CONTEXT_CTX(axc), axr->axr_timeout, axr->axr_priority,
1196 	    0, &(axr->axr_oid), 0);
1197 	if (packetid == 0) {
1198 		agentx_log_axc_warn(axc, "couldn't generate %s",
1199 		    ax_pdutype2string(AX_PDU_TYPE_REGISTER));
1200 		agentx_reset(ax);
1201 		return -1;
1202 	}
1203 	agentx_log_axc_info(axc, "region %s: opening",
1204 	    ax_oid2string(&(axr->axr_oid)));
1205 	axr->axr_cstate = AX_CSTATE_WAITOPEN;
1206 	return agentx_request(ax, packetid, agentx_region_finalize, axr);
1207 }
1208 
1209 static int
1210 agentx_region_finalize(struct ax_pdu *pdu, void *cookie)
1211 {
1212 	struct agentx_region *axr = cookie;
1213 	struct agentx_context *axc = axr->axr_axc;
1214 	struct agentx_index *axi;
1215 	struct agentx_object *axo;
1216 
1217 #ifdef AX_DEBUG
1218 	if (axr->axr_cstate != AX_CSTATE_WAITOPEN)
1219 		agentx_log_axc_fatalx(axc, "%s: not expecting region open",
1220 		    __func__);
1221 #endif
1222 
1223 	if (pdu->ap_payload.ap_response.ap_error == AX_PDU_ERROR_NOERROR) {
1224 		axr->axr_cstate = AX_CSTATE_OPEN;
1225 		agentx_log_axc_info(axc, "region %s: open",
1226 		    ax_oid2string(&(axr->axr_oid)));
1227 	} else if (pdu->ap_payload.ap_response.ap_error ==
1228 	    AX_PDU_ERROR_DUPLICATEREGISTRATION) {
1229 		axr->axr_cstate = AX_CSTATE_CLOSE;
1230 		/* Try at lower priority: first come first serve */
1231 		if ((++axr->axr_priority) != 0) {
1232 			agentx_log_axc_warnx(axc, "region %s: duplicate, "
1233 			    "reducing priority",
1234 			    ax_oid2string(&(axr->axr_oid)));
1235 			return agentx_region_start(axr);
1236 		}
1237 		agentx_log_axc_info(axc, "region %s: duplicate, can't "
1238 		    "reduce priority, ignoring",
1239 		    ax_oid2string(&(axr->axr_oid)));
1240 	} else {
1241 		axr->axr_cstate = AX_CSTATE_CLOSE;
1242 		agentx_log_axc_warnx(axc, "region %s: %s",
1243 		     ax_oid2string(&(axr->axr_oid)),
1244 		     ax_error2string(pdu->ap_payload.ap_response.ap_error));
1245 		return -1;
1246 	}
1247 
1248 	if (axr->axr_dstate == AX_DSTATE_CLOSE) {
1249 		if (agentx_region_close(axr) == -1)
1250 			return -1;
1251 	} else {
1252 		TAILQ_FOREACH(axi, &(axr->axr_indices), axi_axr_indices) {
1253 			if (agentx_index_start(axi) == -1)
1254 				return -1;
1255 		}
1256 		TAILQ_FOREACH(axo, &(axr->axr_objects), axo_axr_objects) {
1257 			if (agentx_object_start(axo) == -1)
1258 				return -1;
1259 		}
1260 	}
1261 	return 0;
1262 }
1263 
1264 static int
1265 agentx_region_close(struct agentx_region *axr)
1266 {
1267 	struct agentx_context *axc = axr->axr_axc;
1268 	struct agentx_session *axs = axc->axc_axs;
1269 	struct agentx *ax = axs->axs_ax;
1270 	uint32_t packetid;
1271 
1272 #ifdef AX_DEBUG
1273 	if (axr->axr_cstate != AX_CSTATE_OPEN)
1274 		agentx_log_axc_fatalx(axc, "%s: unexpected region close",
1275 		    __func__);
1276 #endif
1277 
1278 	axr->axr_cstate = AX_CSTATE_WAITCLOSE;
1279 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
1280 		return 0;
1281 
1282 	packetid = ax_unregister(ax->ax_ax, axs->axs_id,
1283 	    AGENTX_CONTEXT_CTX(axc), axr->axr_priority, 0, &(axr->axr_oid),
1284 	    0);
1285 	if (packetid == 0) {
1286 		agentx_log_axc_warn(axc, "couldn't generate %s",
1287 		    ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
1288 		agentx_reset(ax);
1289 		return -1;
1290 	}
1291 	agentx_log_axc_info(axc, "region %s: closing",
1292 	    ax_oid2string(&(axr->axr_oid)));
1293 	return agentx_request(ax, packetid, agentx_region_close_finalize,
1294 	    axr);
1295 }
1296 
1297 static int
1298 agentx_region_close_finalize(struct ax_pdu *pdu, void *cookie)
1299 {
1300 	struct agentx_region *axr = cookie;
1301 	struct agentx_context *axc = axr->axr_axc;
1302 	struct agentx_session *axs = axc->axc_axs;
1303 	struct agentx *ax = axs->axs_ax;
1304 	int axfree = ax->ax_free;
1305 
1306 #ifdef AX_DEBUG
1307 	if (axr->axr_cstate != AX_CSTATE_WAITCLOSE)
1308 		agentx_log_axc_fatalx(axc, "%s: unexpected region close",
1309 		    __func__);
1310 #endif
1311 
1312 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
1313 		agentx_log_axc_warnx(axc, "closing %s: %s",
1314 		    ax_oid2string(&(axr->axr_oid)),
1315 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
1316 		agentx_reset(ax);
1317 		return -1;
1318 	}
1319 
1320 	ax->ax_free = 1;
1321 	axr->axr_priority = AX_PRIORITY_DEFAULT;
1322 	axr->axr_cstate = AX_CSTATE_CLOSE;
1323 
1324 	agentx_log_axc_info(axc, "region %s: closed",
1325 	    ax_oid2string(&(axr->axr_oid)));
1326 
1327 	if (axc->axc_cstate == AX_CSTATE_OPEN &&
1328 	    axr->axr_dstate == AX_DSTATE_OPEN)
1329 		agentx_region_start(axr);
1330 
1331 	if (!axfree)
1332 		agentx_free_finalize(ax);
1333 	return 0;
1334 }
1335 
1336 void
1337 agentx_region_free(struct agentx_region *axr)
1338 {
1339 	struct agentx_index *axi, *taxi;
1340 	struct agentx_object *axo, *taxo;
1341 	struct agentx *ax;
1342 	int axfree;
1343 
1344 	if (axr == NULL)
1345 		return;
1346 
1347 	ax = axr->axr_axc->axc_axs->axs_ax;
1348 	axfree = ax->ax_free;
1349 	ax->ax_free = 1;
1350 
1351 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
1352 		agentx_log_axc_fatalx(axr->axr_axc, "%s: double free",
1353 		    __func__);
1354 
1355 	axr->axr_dstate = AX_DSTATE_CLOSE;
1356 
1357 	TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi) {
1358 		if (axi->axi_dstate != AX_DSTATE_CLOSE)
1359 			agentx_index_free(axi);
1360 	}
1361 
1362 	TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo) {
1363 		if (axo->axo_dstate != AX_DSTATE_CLOSE)
1364 			agentx_object_free(axo);
1365 	}
1366 
1367 	if (axr->axr_cstate == AX_CSTATE_OPEN)
1368 		agentx_region_close(axr);
1369 
1370 	if (!axfree)
1371 		agentx_free_finalize(ax);
1372 }
1373 
1374 static void
1375 agentx_region_free_finalize(struct agentx_region *axr)
1376 {
1377 	struct agentx_context *axc = axr->axr_axc;
1378 	struct agentx_index *axi, *taxi;
1379 	struct agentx_object *axo, *taxo;
1380 
1381 	TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo)
1382 		agentx_object_free_finalize(axo);
1383 	TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi)
1384 		agentx_index_free_finalize(axi);
1385 
1386 	if (!TAILQ_EMPTY(&(axr->axr_indices)) ||
1387 	    !TAILQ_EMPTY(&(axr->axr_objects)) ||
1388 	    axr->axr_cstate != AX_CSTATE_CLOSE ||
1389 	    axr->axr_dstate != AX_DSTATE_CLOSE)
1390 		return;
1391 
1392 	TAILQ_REMOVE(&(axc->axc_regions), axr, axr_axc_regions);
1393 	free(axr);
1394 }
1395 
1396 static void
1397 agentx_region_reset(struct agentx_region *axr)
1398 {
1399 	struct agentx_index *axi, *taxi;
1400 	struct agentx_object *axo, *taxo;
1401 	struct agentx *ax = axr->axr_axc->axc_axs->axs_ax;
1402 	int axfree = ax->ax_free;
1403 
1404 	axr->axr_cstate = AX_CSTATE_CLOSE;
1405 	axr->axr_priority = AX_PRIORITY_DEFAULT;
1406 	ax->ax_free = 1;
1407 
1408 	TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi)
1409 		agentx_index_reset(axi);
1410 	TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo)
1411 		agentx_object_reset(axo);
1412 
1413 	if (!axfree)
1414 		agentx_free_finalize(ax);
1415 }
1416 
1417 struct agentx_index *
1418 agentx_index_integer_new(struct agentx_region *axr, uint32_t oid[],
1419     size_t oidlen)
1420 {
1421 	struct ax_varbind vb;
1422 	const char *errstr;
1423 
1424 	vb.avb_type = AX_DATA_TYPE_INTEGER;
1425 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1426 #ifdef AX_DEBUG
1427 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1428 #else
1429 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1430 		return NULL;
1431 #endif
1432 	}
1433 	vb.avb_data.avb_int32 = 0;
1434 
1435 	return agentx_index(axr, &vb, AXI_TYPE_NEW);
1436 }
1437 
1438 struct agentx_index *
1439 agentx_index_integer_any(struct agentx_region *axr, uint32_t oid[],
1440     size_t oidlen)
1441 {
1442 	struct ax_varbind vb;
1443 	const char *errstr;
1444 
1445 	vb.avb_type = AX_DATA_TYPE_INTEGER;
1446 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1447 #ifdef AX_DEBUG
1448 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1449 #else
1450 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1451 		return NULL;
1452 #endif
1453 	}
1454 	vb.avb_data.avb_int32 = 0;
1455 
1456 	return agentx_index(axr, &vb, AXI_TYPE_ANY);
1457 }
1458 
1459 struct agentx_index *
1460 agentx_index_integer_value(struct agentx_region *axr, uint32_t oid[],
1461     size_t oidlen, int32_t value)
1462 {
1463 	struct ax_varbind vb;
1464 	const char *errstr;
1465 
1466 	if (value < 0) {
1467 #ifdef AX_DEBUG
1468 		agentx_log_axc_fatalx(axr->axr_axc, "%s: value < 0", __func__);
1469 #else
1470 		agentx_log_axc_warnx(axr->axr_axc, "%s: value < 0", __func__);
1471 		errno = EINVAL;
1472 		return NULL;
1473 #endif
1474 	}
1475 
1476 	vb.avb_type = AX_DATA_TYPE_INTEGER;
1477 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1478 #ifdef AX_DEBUG
1479 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1480 #else
1481 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1482 		return NULL;
1483 #endif
1484 	}
1485 	vb.avb_data.avb_int32 = value;
1486 
1487 	return agentx_index(axr, &vb, AXI_TYPE_VALUE);
1488 }
1489 
1490 struct agentx_index *
1491 agentx_index_integer_dynamic(struct agentx_region *axr, uint32_t oid[],
1492     size_t oidlen)
1493 {
1494 	struct ax_varbind vb;
1495 	const char *errstr;
1496 
1497 	vb.avb_type = AX_DATA_TYPE_INTEGER;
1498 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1499 #ifdef AX_DEBUG
1500 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1501 #else
1502 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1503 		return NULL;
1504 #endif
1505 	}
1506 
1507 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
1508 }
1509 
1510 struct agentx_index *
1511 agentx_index_string_dynamic(struct agentx_region *axr, uint32_t oid[],
1512     size_t oidlen)
1513 {
1514 	struct ax_varbind vb;
1515 	const char *errstr;
1516 
1517 	vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
1518 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1519 #ifdef AX_DEBUG
1520 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1521 #else
1522 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1523 		return NULL;
1524 #endif
1525 	}
1526 	vb.avb_data.avb_ostring.aos_slen = 0;
1527 	vb.avb_data.avb_ostring.aos_string = NULL;
1528 
1529 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
1530 }
1531 
1532 struct agentx_index *
1533 agentx_index_nstring_dynamic(struct agentx_region *axr, uint32_t oid[],
1534     size_t oidlen, size_t vlen)
1535 {
1536 	struct ax_varbind vb;
1537 	const char *errstr;
1538 
1539 	if (vlen == 0 || vlen > AGENTX_OID_MAX_LEN) {
1540 #ifdef AX_DEBUG
1541 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid string "
1542 		    "length: %zu\n", __func__, vlen);
1543 #else
1544 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid string "
1545 		    "length: %zu\n", __func__, vlen);
1546 		errno = EINVAL;
1547 		return NULL;
1548 #endif
1549 	}
1550 
1551 	vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
1552 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1553 #ifdef AX_DEBUG
1554 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1555 #else
1556 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1557 		return NULL;
1558 #endif
1559 	}
1560 	vb.avb_data.avb_ostring.aos_slen = vlen;
1561 	vb.avb_data.avb_ostring.aos_string = NULL;
1562 
1563 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
1564 }
1565 
1566 struct agentx_index *
1567 agentx_index_oid_dynamic(struct agentx_region *axr, uint32_t oid[],
1568     size_t oidlen)
1569 {
1570 	struct ax_varbind vb;
1571 	const char *errstr;
1572 
1573 	vb.avb_type = AX_DATA_TYPE_OID;
1574 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1575 #ifdef AX_DEBUG
1576 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1577 #else
1578 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1579 		return NULL;
1580 #endif
1581 	}
1582 	vb.avb_data.avb_oid.aoi_idlen = 0;
1583 
1584 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
1585 }
1586 
1587 struct agentx_index *
1588 agentx_index_noid_dynamic(struct agentx_region *axr, uint32_t oid[],
1589     size_t oidlen, size_t vlen)
1590 {
1591 	struct ax_varbind vb;
1592 	const char *errstr;
1593 
1594 	if (vlen < AGENTX_OID_MIN_LEN || vlen > AGENTX_OID_MAX_LEN) {
1595 #ifdef AX_DEBUG
1596 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid string "
1597 		    "length: %zu\n", __func__, vlen);
1598 #else
1599 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid string "
1600 		    "length: %zu\n", __func__, vlen);
1601 		errno = EINVAL;
1602 		return NULL;
1603 #endif
1604 	}
1605 
1606 	vb.avb_type = AX_DATA_TYPE_OID;
1607 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1608 #ifdef AX_DEBUG
1609 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1610 #else
1611 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1612 		return NULL;
1613 #endif
1614 	}
1615 	vb.avb_data.avb_oid.aoi_idlen = vlen;
1616 
1617 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
1618 }
1619 
1620 struct agentx_index *
1621 agentx_index_ipaddress_dynamic(struct agentx_region *axr, uint32_t oid[],
1622     size_t oidlen)
1623 {
1624 	struct ax_varbind vb;
1625 	const char *errstr;
1626 
1627 	vb.avb_type = AX_DATA_TYPE_IPADDRESS;
1628 	if (agentx_oidfill(&(vb.avb_oid), oid, oidlen, &errstr) == -1) {
1629 #ifdef AX_DEBUG
1630 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1631 #else
1632 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1633 		return NULL;
1634 #endif
1635 	}
1636 	vb.avb_data.avb_ostring.aos_string = NULL;
1637 
1638 	return agentx_index(axr, &vb, AXI_TYPE_DYNAMIC);
1639 }
1640 
1641 static struct agentx_index *
1642 agentx_index(struct agentx_region *axr, struct ax_varbind *vb,
1643     enum agentx_index_type type)
1644 {
1645 	struct agentx_index *axi;
1646 
1647 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
1648 		agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
1649 		    __func__);
1650 	if (ax_oid_cmp(&(axr->axr_oid), &(vb->avb_oid)) != -2) {
1651 #ifdef AX_DEBUG
1652 		agentx_log_axc_fatalx(axr->axr_axc, "%s: oid is not child "
1653 		    "of region %s", __func__,
1654 		    ax_oid2string(&(vb->avb_oid)));
1655 #else
1656 		agentx_log_axc_warnx(axr->axr_axc, "%s: oid is not child of "
1657 		    "region %s", __func__, ax_oid2string(&(vb->avb_oid)));
1658 		errno = EINVAL;
1659 		return NULL;
1660 #endif
1661 	}
1662 
1663 	if ((axi = calloc(1, sizeof(*axi))) == NULL)
1664 		return NULL;
1665 
1666 	axi->axi_axr = axr;
1667 	axi->axi_type = type;
1668 	bcopy(vb, &(axi->axi_vb), sizeof(*vb));
1669 	axi->axi_cstate = AX_CSTATE_CLOSE;
1670 	axi->axi_dstate = AX_DSTATE_OPEN;
1671 	TAILQ_INSERT_HEAD(&(axr->axr_indices), axi, axi_axr_indices);
1672 
1673 	if (axr->axr_cstate == AX_CSTATE_OPEN)
1674 		agentx_index_start(axi);
1675 
1676 	return axi;
1677 }
1678 
1679 static int
1680 agentx_index_start(struct agentx_index *axi)
1681 {
1682 	struct agentx_region *axr = axi->axi_axr;
1683 	struct agentx_context *axc = axr->axr_axc;
1684 	struct agentx_session *axs = axc->axc_axs;
1685 	struct agentx *ax = axs->axs_ax;
1686 	uint32_t packetid;
1687 	int flags = 0;
1688 
1689 #ifdef AX_DEBUG
1690 	if (axr->axr_cstate != AX_CSTATE_OPEN ||
1691 	    axi->axi_cstate != AX_CSTATE_CLOSE ||
1692 	    axi->axi_dstate != AX_DSTATE_OPEN)
1693 		agentx_log_axc_fatalx(axc, "%s: unexpected index allocation",
1694 		    __func__);
1695 #endif
1696 
1697 	axi->axi_cstate = AX_CSTATE_WAITOPEN;
1698 
1699 	if (axi->axi_type == AXI_TYPE_NEW)
1700 		flags = AX_PDU_FLAG_NEW_INDEX;
1701 	else if (axi->axi_type == AXI_TYPE_ANY)
1702 		flags = AX_PDU_FLAG_ANY_INDEX;
1703 	else if (axi->axi_type == AXI_TYPE_DYNAMIC) {
1704 		agentx_index_finalize(NULL, axi);
1705 		return 0;
1706 	}
1707 
1708 	/* We might be able to bundle, but if we fail we'd have to reorganise */
1709 	packetid = ax_indexallocate(ax->ax_ax, flags, axs->axs_id,
1710 	    AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
1711 	if (packetid == 0) {
1712 		agentx_log_axc_warn(axc, "couldn't generate %s",
1713 		    ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
1714 		agentx_reset(ax);
1715 		return -1;
1716 	}
1717 	if (axi->axi_type == AXI_TYPE_VALUE)
1718 		agentx_log_axc_info(axc, "index %s: allocating '%d'",
1719 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
1720 		    axi->axi_vb.avb_data.avb_int32);
1721 	else if (axi->axi_type == AXI_TYPE_ANY)
1722 		agentx_log_axc_info(axc, "index %s: allocating any index",
1723 		    ax_oid2string(&(axi->axi_vb.avb_oid)));
1724 	else if (axi->axi_type == AXI_TYPE_NEW)
1725 		agentx_log_axc_info(axc, "index %s: allocating new index",
1726 		    ax_oid2string(&(axi->axi_vb.avb_oid)));
1727 
1728 	return agentx_request(ax, packetid, agentx_index_finalize, axi);
1729 }
1730 
1731 static int
1732 agentx_index_finalize(struct ax_pdu *pdu, void *cookie)
1733 {
1734 	struct agentx_index *axi = cookie;
1735 	struct agentx_region *axr = axi->axi_axr;
1736 	struct agentx_context *axc = axr->axr_axc;
1737 	struct ax_pdu_response *resp;
1738 	size_t i;
1739 
1740 #ifdef AX_DEBUG
1741 	if (axi->axi_cstate != AX_CSTATE_WAITOPEN)
1742 		agentx_log_axc_fatalx(axc,
1743 		    "%s: not expecting index allocate", __func__);
1744 #endif
1745 	if (axi->axi_type == AXI_TYPE_DYNAMIC) {
1746 		axi->axi_cstate = AX_CSTATE_OPEN;
1747 		goto objects_start;
1748 	}
1749 
1750 	resp = &(pdu->ap_payload.ap_response);
1751 	if (resp->ap_error != AX_PDU_ERROR_NOERROR) {
1752 		axi->axi_cstate = AX_CSTATE_CLOSE;
1753 		agentx_log_axc_warnx(axc, "index %s: %s",
1754 		    ax_oid2string(&(axr->axr_oid)),
1755 		    ax_error2string(resp->ap_error));
1756 		return 0;
1757 	}
1758 	axi->axi_cstate = AX_CSTATE_OPEN;
1759 	if (resp->ap_nvarbind != 1) {
1760 		agentx_log_axc_warnx(axc, "index %s: unexpected number of "
1761 		    "indices", ax_oid2string(&(axr->axr_oid)));
1762 		axi->axi_cstate = AX_CSTATE_CLOSE;
1763 		return -1;
1764 	}
1765 	if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
1766 		agentx_log_axc_warnx(axc, "index %s: unexpected index type",
1767 		    ax_oid2string(&(axr->axr_oid)));
1768 		axi->axi_cstate = AX_CSTATE_CLOSE;
1769 		return -1;
1770 	}
1771 	if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
1772 	    &(axi->axi_vb.avb_oid)) != 0) {
1773 		agentx_log_axc_warnx(axc, "index %s: unexpected oid",
1774 		    ax_oid2string(&(axr->axr_oid)));
1775 		axi->axi_cstate = AX_CSTATE_CLOSE;
1776 		return -1;
1777 	}
1778 
1779 	switch (axi->axi_vb.avb_type) {
1780 	case AX_DATA_TYPE_INTEGER:
1781 		if (axi->axi_type == AXI_TYPE_NEW ||
1782 		    axi->axi_type == AXI_TYPE_ANY)
1783 			axi->axi_vb.avb_data.avb_int32 =
1784 			    resp->ap_varbindlist[0].avb_data.avb_int32;
1785 		else if (axi->axi_vb.avb_data.avb_int32 !=
1786 		    resp->ap_varbindlist[0].avb_data.avb_int32) {
1787 			agentx_log_axc_warnx(axc, "index %s: unexpected "
1788 			    "index value", ax_oid2string(&(axr->axr_oid)));
1789 			axi->axi_cstate = AX_CSTATE_CLOSE;
1790 			return -1;
1791 		}
1792 		agentx_log_axc_info(axc, "index %s: allocated '%d'",
1793 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
1794 		    axi->axi_vb.avb_data.avb_int32);
1795 		break;
1796 	default:
1797 		agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
1798 		    __func__);
1799 	}
1800 
1801 	if (axi->axi_dstate == AX_DSTATE_CLOSE)
1802 		return agentx_index_close(axi);
1803 
1804  objects_start:
1805 	/* TODO Make use of range_subid register */
1806 	for (i = 0; i < axi->axi_objectlen; i++) {
1807 		if (axi->axi_object[i]->axo_dstate == AX_DSTATE_OPEN) {
1808 			if (agentx_object_start(axi->axi_object[i]) == -1)
1809 				return -1;
1810 		}
1811 	}
1812 	return 0;
1813 }
1814 
1815 void
1816 agentx_index_free(struct agentx_index *axi)
1817 {
1818 	size_t i;
1819 	struct agentx_object *axo;
1820 	struct agentx *ax;
1821 	int axfree;
1822 
1823 	if (axi == NULL)
1824 		return;
1825 
1826 	ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
1827 	axfree = ax->ax_free;
1828 	ax->ax_free = 1;
1829 
1830 	if (axi->axi_dstate == AX_DSTATE_CLOSE)
1831 		agentx_log_axc_fatalx(axi->axi_axr->axr_axc,
1832 		    "%s: double free", __func__);
1833 
1834 	/* TODO Do a range_subid unregister before freeing */
1835 	for (i = 0; i < axi->axi_objectlen; i++) {
1836 		axo = axi->axi_object[i];
1837 		if (axo->axo_dstate != AX_DSTATE_CLOSE) {
1838 			agentx_object_free(axo);
1839 			if (axi->axi_object[i] != axo)
1840 				i--;
1841 		}
1842 	}
1843 
1844 	axi->axi_dstate = AX_DSTATE_CLOSE;
1845 
1846 	if (axi->axi_cstate == AX_CSTATE_OPEN)
1847 		(void) agentx_index_close(axi);
1848 	if (!axfree)
1849 		agentx_free_finalize(ax);
1850 }
1851 
1852 static void
1853 agentx_index_free_finalize(struct agentx_index *axi)
1854 {
1855 	struct agentx_region *axr = axi->axi_axr;
1856 
1857 	if (axi->axi_cstate != AX_CSTATE_CLOSE ||
1858 	    axi->axi_dstate != AX_DSTATE_CLOSE ||
1859 	    axi->axi_objectlen != 0)
1860 		return;
1861 
1862 	TAILQ_REMOVE(&(axr->axr_indices), axi, axi_axr_indices);
1863 	ax_varbind_free(&(axi->axi_vb));
1864 	free(axi->axi_object);
1865 	free(axi);
1866 }
1867 
1868 static void
1869 agentx_index_reset(struct agentx_index *axi)
1870 {
1871 	struct agentx *ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
1872 
1873 	axi->axi_cstate = AX_CSTATE_CLOSE;
1874 
1875 	if (!ax->ax_free)
1876 		agentx_free_finalize(ax);
1877 }
1878 
1879 static int
1880 agentx_index_close(struct agentx_index *axi)
1881 {
1882 	struct agentx_region *axr = axi->axi_axr;
1883 	struct agentx_context *axc = axr->axr_axc;
1884 	struct agentx_session *axs = axc->axc_axs;
1885 	struct agentx *ax = axs->axs_ax;
1886 	uint32_t packetid;
1887 
1888 #ifdef AX_DEBUG
1889 	if (axi->axi_cstate != AX_CSTATE_OPEN)
1890 		agentx_log_axc_fatalx(axc,
1891 		    "%s: unexpected index deallocation", __func__);
1892 #endif
1893 
1894 	axi->axi_cstate = AX_CSTATE_WAITCLOSE;
1895 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
1896 		return 0;
1897 
1898 	/* We might be able to bundle, but if we fail we'd have to reorganise */
1899 	packetid = ax_indexdeallocate(ax->ax_ax, axs->axs_id,
1900 	    AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
1901 	if (packetid == 0) {
1902 		agentx_log_axc_warn(axc, "couldn't generate %s",
1903 		    ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
1904 		agentx_reset(ax);
1905 		return -1;
1906 	}
1907 	agentx_log_axc_info(axc, "index %s: deallocating",
1908 	    ax_oid2string(&(axi->axi_vb.avb_oid)));
1909 	return agentx_request(ax, packetid, agentx_index_close_finalize,
1910 	    axi);
1911 }
1912 
1913 static int
1914 agentx_index_close_finalize(struct ax_pdu *pdu, void *cookie)
1915 {
1916 	struct agentx_index *axi = cookie;
1917 	struct agentx_region *axr = axi->axi_axr;
1918 	struct agentx_context *axc = axr->axr_axc;
1919 	struct agentx_session *axs = axc->axc_axs;
1920 	struct agentx *ax = axs->axs_ax;
1921 	struct ax_pdu_response *resp = &(pdu->ap_payload.ap_response);
1922 	int axfree = ax->ax_free;
1923 
1924 #ifdef AX_DEBUG
1925 	if (axi->axi_cstate != AX_CSTATE_WAITCLOSE)
1926 		agentx_log_axc_fatalx(axc, "%s: unexpected indexdeallocate",
1927 		    __func__);
1928 #endif
1929 
1930 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
1931 		agentx_log_axc_warnx(axc,
1932 		    "index %s: couldn't deallocate: %s",
1933 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
1934 		    ax_error2string(resp->ap_error));
1935 		agentx_reset(ax);
1936 		return -1;
1937 	}
1938 
1939 	if (resp->ap_nvarbind != 1) {
1940 		agentx_log_axc_warnx(axc,
1941 		    "index %s: unexpected number of indices",
1942 		    ax_oid2string(&(axr->axr_oid)));
1943 		agentx_reset(ax);
1944 		return -1;
1945 	}
1946 	if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
1947 		agentx_log_axc_warnx(axc, "index %s: unexpected index type",
1948 		    ax_oid2string(&(axr->axr_oid)));
1949 		agentx_reset(ax);
1950 		return -1;
1951 	}
1952 	if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
1953 	    &(axi->axi_vb.avb_oid)) != 0) {
1954 		agentx_log_axc_warnx(axc, "index %s: unexpected oid",
1955 		    ax_oid2string(&(axr->axr_oid)));
1956 		agentx_reset(ax);
1957 		return -1;
1958 	}
1959 	switch (axi->axi_vb.avb_type) {
1960 	case AX_DATA_TYPE_INTEGER:
1961 		if (axi->axi_vb.avb_data.avb_int32 !=
1962 		    resp->ap_varbindlist[0].avb_data.avb_int32) {
1963 			agentx_log_axc_warnx(axc,
1964 			    "index %s: unexpected index value",
1965 			    ax_oid2string(&(axr->axr_oid)));
1966 			agentx_reset(ax);
1967 			return -1;
1968 		}
1969 		break;
1970 	default:
1971 		agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
1972 		    __func__);
1973 	}
1974 
1975 	axi->axi_cstate = AX_CSTATE_CLOSE;
1976 	ax->ax_free = 1;
1977 
1978 	agentx_log_axc_info(axc, "index %s: deallocated",
1979 	    ax_oid2string(&(axi->axi_vb.avb_oid)));
1980 
1981 	if (axr->axr_cstate == AX_CSTATE_OPEN &&
1982 	    axi->axi_dstate == AX_DSTATE_OPEN)
1983 		agentx_index_start(axi);
1984 
1985 	if (!axfree)
1986 		agentx_free_finalize(ax);
1987 	return 0;
1988 }
1989 
1990 struct agentx_object *
1991 agentx_object(struct agentx_region *axr, uint32_t oid[], size_t oidlen,
1992     struct agentx_index *axi[], size_t axilen, int implied,
1993     void (*get)(struct agentx_varbind *))
1994 {
1995 	struct agentx_object *axo, **taxo, axo_search;
1996 	struct agentx_index *laxi;
1997 	const char *errstr;
1998 	int ready = 1;
1999 	size_t i, j;
2000 
2001 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
2002 		agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
2003 		    __func__);
2004 	if (axilen > AGENTX_OID_INDEX_MAX_LEN) {
2005 #ifdef AX_DEBUG
2006 		agentx_log_axc_fatalx(axr->axr_axc, "%s: indexlen > %d",
2007 		    __func__, AGENTX_OID_INDEX_MAX_LEN);
2008 #else
2009 		agentx_log_axc_warnx(axr->axr_axc, "%s: indexlen > %d",
2010 		    __func__, AGENTX_OID_INDEX_MAX_LEN);
2011 		errno = EINVAL;
2012 		return NULL;
2013 #endif
2014 	}
2015 
2016 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
2017 #ifdef AX_DEBUG
2018 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
2019 #else
2020 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
2021 		return NULL;
2022 #endif
2023 	}
2024 
2025 	do {
2026 		if (RB_FIND(axc_objects, &(axr->axr_axc->axc_objects),
2027 		    &axo_search) != NULL) {
2028 #ifdef AX_DEBUG
2029 			agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid "
2030 			    "parent child object relationship", __func__);
2031 #else
2032 			agentx_log_axc_warnx(axr->axr_axc, "%s: invalid "
2033 			    "parent child object relationship", __func__);
2034 			errno = EINVAL;
2035 			return NULL;
2036 #endif
2037 		}
2038 		axo_search.axo_oid.aoi_idlen--;
2039 	} while (axo_search.axo_oid.aoi_idlen > 0);
2040 	axo_search.axo_oid.aoi_idlen = oidlen;
2041 	axo = RB_NFIND(axc_objects, &(axr->axr_axc->axc_objects), &axo_search);
2042 	if (axo != NULL &&
2043 	    ax_oid_cmp(&(axo->axo_oid), &(axo_search.axo_oid)) == 2) {
2044 #ifdef AX_DEBUG
2045 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid parent "
2046 		    "child object relationship", __func__);
2047 #else
2048 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid parent "
2049 		    "child object relationship", __func__);
2050 		errno = EINVAL;
2051 		return NULL;
2052 #endif
2053 	}
2054 	if (implied == 1) {
2055 		laxi = axi[axilen - 1];
2056 		if (laxi->axi_vb.avb_type == AX_DATA_TYPE_OCTETSTRING) {
2057 			if (laxi->axi_vb.avb_data.avb_ostring.aos_slen != 0) {
2058 #ifdef AX_DEBUG
2059 				agentx_log_axc_fatalx(axr->axr_axc,
2060 				    "%s: implied can only be used on strings "
2061 				    "of dynamic length", __func__);
2062 #else
2063 				agentx_log_axc_warnx(axr->axr_axc,
2064 				    "%s: implied can only be used on strings "
2065 				    "of dynamic length", __func__);
2066 				errno = EINVAL;
2067 				return NULL;
2068 #endif
2069 			}
2070 		} else if (laxi->axi_vb.avb_type == AX_DATA_TYPE_OID) {
2071 			if (laxi->axi_vb.avb_data.avb_oid.aoi_idlen != 0) {
2072 #ifdef AX_DEBUG
2073 				agentx_log_axc_fatalx(axr->axr_axc,
2074 				    "%s: implied can only be used on oids of "
2075 				    "dynamic length", __func__);
2076 #else
2077 				agentx_log_axc_warnx(axr->axr_axc,
2078 				    "%s: implied can only be used on oids of "
2079 				    "dynamic length", __func__);
2080 				errno = EINVAL;
2081 				return NULL;
2082 #endif
2083 			}
2084 		} else {
2085 #ifdef AX_DEBUG
2086 			agentx_log_axc_fatalx(axr->axr_axc, "%s: implied "
2087 			    "can only be set on oid and string indices",
2088 			    __func__);
2089 #else
2090 			agentx_log_axc_warnx(axr->axr_axc, "%s: implied can "
2091 			    "only be set on oid and string indices", __func__);
2092 			errno = EINVAL;
2093 			return NULL;
2094 #endif
2095 		}
2096 	}
2097 
2098 	ready = axr->axr_cstate == AX_CSTATE_OPEN;
2099 	if ((axo = calloc(1, sizeof(*axo))) == NULL)
2100 		return NULL;
2101 	axo->axo_axr = axr;
2102 	bcopy(&(axo_search.axo_oid), &(axo->axo_oid), sizeof(axo->axo_oid));
2103 	for (i = 0; i < axilen; i++) {
2104 		axo->axo_index[i] = axi[i];
2105 		if (axi[i]->axi_objectlen == axi[i]->axi_objectsize) {
2106 			taxo = recallocarray(axi[i]->axi_object,
2107 			    axi[i]->axi_objectlen, axi[i]->axi_objectlen + 1,
2108 			    sizeof(*axi[i]->axi_object));
2109 			if (taxo == NULL) {
2110 				free(axo);
2111 				return NULL;
2112 			}
2113 			axi[i]->axi_object = taxo;
2114 			axi[i]->axi_objectsize = axi[i]->axi_objectlen + 1;
2115 		}
2116 		for (j = 0; j < axi[i]->axi_objectlen; j++) {
2117 			if (ax_oid_cmp(&(axo->axo_oid),
2118 			    &(axi[i]->axi_object[j]->axo_oid)) < 0) {
2119 				memmove(&(axi[i]->axi_object[j + 1]),
2120 				    &(axi[i]->axi_object[j]),
2121 				    sizeof(*(axi[i]->axi_object)) *
2122 				    (axi[i]->axi_objectlen - j));
2123 				break;
2124 			}
2125 		}
2126 		axi[i]->axi_object[j] = axo;
2127 		axi[i]->axi_objectlen++;
2128 		if (axi[i]->axi_cstate != AX_CSTATE_OPEN)
2129 			ready = 0;
2130 	}
2131 	axo->axo_indexlen = axilen;
2132 	axo->axo_implied = implied;
2133 	axo->axo_timeout = 0;
2134 	axo->axo_lock = 0;
2135 	axo->axo_get = get;
2136 	axo->axo_cstate = AX_CSTATE_CLOSE;
2137 	axo->axo_dstate = AX_DSTATE_OPEN;
2138 
2139 	TAILQ_INSERT_TAIL(&(axr->axr_objects), axo, axo_axr_objects);
2140 	RB_INSERT(axc_objects, &(axr->axr_axc->axc_objects), axo);
2141 
2142 	if (ready)
2143 		agentx_object_start(axo);
2144 
2145 	return axo;
2146 }
2147 
2148 static int
2149 agentx_object_start(struct agentx_object *axo)
2150 {
2151 	struct agentx_region *axr = axo->axo_axr;
2152 	struct agentx_context *axc = axr->axr_axc;
2153 	struct agentx_session *axs = axc->axc_axs;
2154 	struct agentx *ax = axs->axs_ax;
2155 	struct ax_oid oid;
2156 	char oids[1024];
2157 	size_t i;
2158 	int needregister = 0;
2159 	uint32_t packetid;
2160 	uint8_t flags = AX_PDU_FLAG_INSTANCE_REGISTRATION;
2161 
2162 #ifdef AX_DEBUG
2163 	if (axr->axr_cstate != AX_CSTATE_OPEN ||
2164 	    axo->axo_cstate != AX_CSTATE_CLOSE ||
2165 	    axo->axo_dstate != AX_DSTATE_OPEN)
2166 		agentx_log_axc_fatalx(axc,
2167 		    "%s: unexpected object registration", __func__);
2168 #endif
2169 
2170 	if (axo->axo_timeout != 0)
2171 		needregister = 1;
2172 	for (i = 0; i < axo->axo_indexlen; i++) {
2173 		if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
2174 			return 0;
2175 		if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
2176 			needregister = 1;
2177 	}
2178 	if (!needregister) {
2179 		axo->axo_cstate = AX_CSTATE_WAITOPEN;
2180 		agentx_object_finalize(NULL, axo);
2181 		return 0;
2182 	}
2183 
2184 	bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
2185 	for (i = 0; i < axo->axo_indexlen; i++) {
2186 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2187 			flags = 0;
2188 			break;
2189 		}
2190 #ifdef AX_DEBUG
2191 		if (axo->axo_index[i]->axi_vb.avb_type !=
2192 		    AX_DATA_TYPE_INTEGER)
2193 			agentx_log_axc_fatalx(axc,
2194 			    "%s: Unsupported allocated index type", __func__);
2195 #endif
2196 		oid.aoi_id[oid.aoi_idlen++] =
2197 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2198 	}
2199 	packetid = ax_register(ax->ax_ax, flags, axs->axs_id,
2200 	    AGENTX_CONTEXT_CTX(axc), axo->axo_timeout,
2201 	    AX_PRIORITY_DEFAULT, 0, &oid, 0);
2202 	if (packetid == 0) {
2203 		agentx_log_axc_warn(axc, "couldn't generate %s",
2204 		    ax_pdutype2string(AX_PDU_TYPE_REGISTER));
2205 		agentx_reset(ax);
2206 		return -1;
2207 	}
2208 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2209 	agentx_log_axc_info(axc, "object %s (%s %s): opening",
2210 	    oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
2211 	axo->axo_cstate = AX_CSTATE_WAITOPEN;
2212 	return agentx_request(ax, packetid, agentx_object_finalize, axo);
2213 }
2214 
2215 static int
2216 agentx_object_finalize(struct ax_pdu *pdu, void *cookie)
2217 {
2218 	struct agentx_object *axo = cookie;
2219 	struct agentx_context *axc = axo->axo_axr->axr_axc;
2220 	struct ax_oid oid;
2221 	char oids[1024];
2222 	size_t i;
2223 	uint8_t flags = 1;
2224 
2225 #ifdef AX_DEBUG
2226 	if (axo->axo_cstate != AX_CSTATE_WAITOPEN)
2227 		agentx_log_axc_fatalx(axc, "%s: not expecting object open",
2228 		    __func__);
2229 #endif
2230 
2231 	if (pdu == NULL) {
2232 		axo->axo_cstate = AX_CSTATE_OPEN;
2233 		return 0;
2234 	}
2235 
2236 	bcopy(&(axo->axo_oid), &oid, sizeof(oid));
2237 	for (i = 0; i < axo->axo_indexlen; i++) {
2238 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2239 			flags = 0;
2240 			break;
2241 		}
2242 #ifdef AX_DEBUG
2243 		if (axo->axo_index[i]->axi_vb.avb_type !=
2244 		    AX_DATA_TYPE_INTEGER)
2245 			agentx_log_axc_fatalx(axc,
2246 			    "%s: Unsupported allocated index type", __func__);
2247 #endif
2248 
2249 		oid.aoi_id[oid.aoi_idlen++] =
2250 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2251 	}
2252 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2253 
2254 	/*
2255 	 * We should only be here for table objects with registered indices.
2256 	 * If we fail here something is misconfigured and the admin should fix
2257 	 * it.
2258 	 */
2259 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
2260 		axo->axo_cstate = AX_CSTATE_CLOSE;
2261 		agentx_log_axc_info(axc, "object %s (%s %s): %s",
2262 		    oids, flags ? "instance" : "region", ax_oid2string(&oid),
2263 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
2264 		return 0;
2265 	}
2266 	axo->axo_cstate = AX_CSTATE_OPEN;
2267 	agentx_log_axc_info(axc, "object %s (%s %s): open", oids,
2268 	    flags ? "instance" : "region", ax_oid2string(&oid));
2269 
2270 	if (axo->axo_dstate == AX_DSTATE_CLOSE)
2271 		return agentx_object_close(axo);
2272 
2273 	return 0;
2274 }
2275 
2276 static int
2277 agentx_object_lock(struct agentx_object *axo)
2278 {
2279 	if (axo->axo_lock == UINT32_MAX) {
2280 		agentx_log_axc_warnx(axo->axo_axr->axr_axc,
2281 		    "%s: axo_lock == %u", __func__, UINT32_MAX);
2282 		return -1;
2283 	}
2284 	axo->axo_lock++;
2285 	return 0;
2286 }
2287 
2288 static void
2289 agentx_object_unlock(struct agentx_object *axo)
2290 {
2291 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2292 
2293 #ifdef AX_DEBUG
2294 	if (axo->axo_lock == 0)
2295 		agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
2296 		    "%s: axo_lock == 0", __func__);
2297 #endif
2298 	axo->axo_lock--;
2299 	if (axo->axo_lock == 0) {
2300 		if (!ax->ax_free)
2301 			agentx_free_finalize(ax);
2302 	}
2303 }
2304 
2305 static int
2306 agentx_object_close(struct agentx_object *axo)
2307 {
2308 	struct agentx_context *axc = axo->axo_axr->axr_axc;
2309 	struct agentx_session *axs = axc->axc_axs;
2310 	struct agentx *ax = axs->axs_ax;
2311 	struct ax_oid oid;
2312 	char oids[1024];
2313 	size_t i;
2314 	int needclose = 0;
2315 	uint32_t packetid;
2316 	uint8_t flags = 1;
2317 
2318 #ifdef AX_DEBUG
2319 	if (axo->axo_cstate != AX_CSTATE_OPEN)
2320 		agentx_log_axc_fatalx(axc, "%s: unexpected object close",
2321 		    __func__);
2322 #endif
2323 
2324 	for (i = 0; i < axo->axo_indexlen; i++) {
2325 #ifdef AX_DEBUG
2326 		if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
2327 			agentx_log_axc_fatalx(axc,
2328 			    "%s: Object open while index closed", __func__);
2329 #endif
2330 		if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
2331 			needclose = 1;
2332 	}
2333 	axo->axo_cstate = AX_CSTATE_WAITCLOSE;
2334 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
2335 		return 0;
2336 	if (!needclose) {
2337 		agentx_object_close_finalize(NULL, axo);
2338 		return 0;
2339 	}
2340 
2341 	bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
2342 	for (i = 0; i < axo->axo_indexlen; i++) {
2343 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2344 			flags = 0;
2345 			break;
2346 		}
2347 #ifdef AX_DEBUG
2348 		if (axo->axo_index[i]->axi_vb.avb_type !=
2349 		    AX_DATA_TYPE_INTEGER)
2350 			agentx_log_axc_fatalx(axc,
2351 			    "%s: Unsupported allocated index type", __func__);
2352 #endif
2353 		oid.aoi_id[oid.aoi_idlen++] =
2354 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2355 	}
2356 	packetid = ax_unregister(ax->ax_ax, axs->axs_id,
2357 	    AGENTX_CONTEXT_CTX(axc), AX_PRIORITY_DEFAULT, 0, &oid, 0);
2358 	if (packetid == 0) {
2359 		agentx_log_axc_warn(axc, "couldn't generate %s",
2360 		    ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
2361 		agentx_reset(ax);
2362 		return -1;
2363 	}
2364 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2365 	agentx_log_axc_info(axc, "object %s (%s %s): closing",
2366 	    oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
2367 	return agentx_request(ax, packetid, agentx_object_close_finalize,
2368 	    axo);
2369 }
2370 
2371 static int
2372 agentx_object_close_finalize(struct ax_pdu *pdu, void *cookie)
2373 {
2374 	struct agentx_object *axo = cookie;
2375 	struct agentx_region *axr = axo->axo_axr;
2376 	struct agentx_context *axc = axr->axr_axc;
2377 	struct agentx_session *axs = axc->axc_axs;
2378 	struct agentx *ax = axs->axs_ax;
2379 	struct ax_oid oid;
2380 	char oids[1024];
2381 	uint8_t flags = 1;
2382 	size_t i;
2383 	int axfree = ax->ax_free;
2384 
2385 #ifdef AX_DEBUG
2386 	if (axo->axo_cstate != AX_CSTATE_WAITCLOSE)
2387 		agentx_log_axc_fatalx(axc,
2388 		    "%s: unexpected object unregister", __func__);
2389 #endif
2390 
2391 	if (pdu != NULL) {
2392 		bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
2393 		for (i = 0; i < axo->axo_indexlen; i++) {
2394 			if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2395 				flags = 0;
2396 				break;
2397 			}
2398 #ifdef AX_DEBUG
2399 			if (axo->axo_index[i]->axi_vb.avb_type !=
2400 			    AX_DATA_TYPE_INTEGER)
2401 				agentx_log_axc_fatalx(axc,
2402 				    "%s: Unsupported allocated index type",
2403 				    __func__);
2404 #endif
2405 			oid.aoi_id[oid.aoi_idlen++] =
2406 			    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2407 		}
2408 		strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2409 		if (pdu->ap_payload.ap_response.ap_error !=
2410 		    AX_PDU_ERROR_NOERROR) {
2411 			agentx_log_axc_warnx(axc,
2412 			    "closing object %s (%s %s): %s", oids,
2413 			    flags ? "instance" : "region",
2414 			    ax_oid2string(&oid), ax_error2string(
2415 			    pdu->ap_payload.ap_response.ap_error));
2416 			agentx_reset(ax);
2417 			return -1;
2418 		}
2419 		agentx_log_axc_info(axc, "object %s (%s %s): closed", oids,
2420 		    flags ? "instance" : "region", ax_oid2string(&oid));
2421 	}
2422 
2423 	ax->ax_free = 1;
2424 	if (axr->axr_cstate == AX_CSTATE_OPEN &&
2425 	    axo->axo_dstate == AX_DSTATE_OPEN)
2426 		agentx_object_start(axo);
2427 
2428 	if (!axfree)
2429 		agentx_free_finalize(ax);
2430 
2431 	return 0;
2432 }
2433 
2434 void
2435 agentx_object_free(struct agentx_object *axo)
2436 {
2437 	struct agentx *ax;
2438 	int axfree;
2439 
2440 	if (axo == NULL)
2441 		return;
2442 
2443 	ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2444 	axfree = ax->ax_free;
2445 	ax->ax_free = 1;
2446 
2447 	if (axo->axo_dstate == AX_DSTATE_CLOSE)
2448 		agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
2449 		    "%s: double free", __func__);
2450 
2451 	axo->axo_dstate = AX_DSTATE_CLOSE;
2452 
2453 	if (axo->axo_cstate == AX_CSTATE_OPEN)
2454 		agentx_object_close(axo);
2455 	if (!axfree)
2456 		agentx_free_finalize(ax);
2457 }
2458 
2459 static void
2460 agentx_object_free_finalize(struct agentx_object *axo)
2461 {
2462 #ifdef AX_DEBUG
2463 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2464 #endif
2465 	size_t i, j;
2466 	int found;
2467 
2468 	if (axo->axo_dstate != AX_DSTATE_CLOSE ||
2469 	    axo->axo_cstate != AX_CSTATE_CLOSE ||
2470 	    axo->axo_lock != 0)
2471 		return;
2472 
2473 	RB_REMOVE(axc_objects, &(axo->axo_axr->axr_axc->axc_objects), axo);
2474 	TAILQ_REMOVE(&(axo->axo_axr->axr_objects), axo, axo_axr_objects);
2475 
2476 	for (i = 0; i < axo->axo_indexlen; i++) {
2477 		found = 0;
2478 		for (j = 0; j < axo->axo_index[i]->axi_objectlen; j++) {
2479 			if (axo->axo_index[i]->axi_object[j] == axo)
2480 				found = 1;
2481 			if (found && j + 1 != axo->axo_index[i]->axi_objectlen)
2482 				axo->axo_index[i]->axi_object[j] =
2483 				    axo->axo_index[i]->axi_object[j + 1];
2484 		}
2485 #ifdef AX_DEBUG
2486 		if (!found)
2487 			agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
2488 			    "%s: object not found in index", __func__);
2489 #endif
2490 		axo->axo_index[i]->axi_objectlen--;
2491 	}
2492 
2493 	free(axo);
2494 }
2495 
2496 static void
2497 agentx_object_reset(struct agentx_object *axo)
2498 {
2499 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2500 
2501 	axo->axo_cstate = AX_CSTATE_CLOSE;
2502 
2503 	if (!ax->ax_free)
2504 		agentx_free_finalize(ax);
2505 }
2506 
2507 static int
2508 agentx_object_cmp(struct agentx_object *o1, struct agentx_object *o2)
2509 {
2510 	return ax_oid_cmp(&(o1->axo_oid), &(o2->axo_oid));
2511 }
2512 
2513 static int
2514 agentx_object_implied(struct agentx_object *axo,
2515     struct agentx_index *axi)
2516 {
2517 	size_t i = 0;
2518 	struct ax_varbind *vb;
2519 
2520 	for (i = 0; i < axo->axo_indexlen; i++) {
2521 		if (axo->axo_index[i] == axi) {
2522 			vb = &axi->axi_vb;
2523 			if (vb->avb_type == AX_DATA_TYPE_OCTETSTRING &&
2524 			    vb->avb_data.avb_ostring.aos_slen != 0)
2525 				return 1;
2526 			else if (vb->avb_type == AX_DATA_TYPE_OID &&
2527 			    vb->avb_data.avb_oid.aoi_idlen != 0)
2528 				return 1;
2529 			else if (i == axo->axo_indexlen - 1)
2530 				return axo->axo_implied;
2531 			return 0;
2532 		}
2533 	}
2534 #ifdef AX_DEBUG
2535 	agentx_log_axc_fatalx(axo->axo_axr->axr_axc, "%s: unsupported index",
2536 	    __func__);
2537 #endif
2538 	return 0;
2539 }
2540 
2541 static void
2542 agentx_get_start(struct agentx_context *axc, struct ax_pdu *pdu)
2543 {
2544 	struct agentx_session *axs = axc->axc_axs;
2545 	struct agentx *ax = axs->axs_ax;
2546 	struct agentx_get *axg, taxg;
2547 	struct ax_pdu_searchrangelist *srl;
2548 	char *logmsg = NULL;
2549 	size_t i, j;
2550 	int fail = 0;
2551 
2552 	if ((axg = calloc(1, sizeof(*axg))) == NULL) {
2553 		taxg.axg_sessionid = pdu->ap_header.aph_sessionid;
2554 		taxg.axg_transactionid = pdu->ap_header.aph_transactionid;
2555 		taxg.axg_packetid = pdu->ap_header.aph_packetid;
2556 		taxg.axg_context_default = axc->axc_name_default;
2557 		taxg.axg_fd = axc->axc_axs->axs_ax->ax_fd;
2558 		agentx_log_axg_warn(&taxg, "Couldn't parse request");
2559 		agentx_reset(ax);
2560 		return;
2561 	}
2562 
2563 	axg->axg_sessionid = pdu->ap_header.aph_sessionid;
2564 	axg->axg_transactionid = pdu->ap_header.aph_transactionid;
2565 	axg->axg_packetid = pdu->ap_header.aph_packetid;
2566 	axg->axg_context_default = axc->axc_name_default;
2567 	axg->axg_fd = axc->axc_axs->axs_ax->ax_fd;
2568 	if (!axc->axc_name_default) {
2569 		axg->axg_context.aos_string =
2570 		    (unsigned char *)strdup((char *)axc->axc_name.aos_string);
2571 		if (axg->axg_context.aos_string == NULL) {
2572 			agentx_log_axg_warn(axg, "Couldn't parse request");
2573 			free(axg);
2574 			agentx_reset(ax);
2575 			return;
2576 		}
2577 	}
2578 	axg->axg_context.aos_slen = axc->axc_name.aos_slen;
2579 	axg->axg_type = pdu->ap_header.aph_type;
2580 	axg->axg_axc = axc;
2581 	TAILQ_INSERT_TAIL(&(ax->ax_getreqs), axg, axg_ax_getreqs);
2582 	if (axg->axg_type == AX_PDU_TYPE_GET ||
2583 	    axg->axg_type == AX_PDU_TYPE_GETNEXT) {
2584 		srl = &(pdu->ap_payload.ap_srl);
2585 		axg->axg_nvarbind = srl->ap_nsr;
2586 	} else {
2587 		axg->axg_nonrep = pdu->ap_payload.ap_getbulk.ap_nonrep;
2588 		axg->axg_maxrep = pdu->ap_payload.ap_getbulk.ap_maxrep;
2589 		srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
2590 		axg->axg_nvarbind = ((srl->ap_nsr - axg->axg_nonrep) *
2591 		    axg->axg_maxrep) + axg->axg_nonrep;
2592 	}
2593 
2594 	if ((axg->axg_varbind = calloc(axg->axg_nvarbind,
2595 	    sizeof(*(axg->axg_varbind)))) == NULL) {
2596 		agentx_log_axg_warn(axg, "Couldn't parse request");
2597 		agentx_get_free(axg);
2598 		agentx_reset(ax);
2599 		return;
2600 	}
2601 
2602 	/* XXX net-snmp doesn't use getbulk, so untested */
2603 	/* Two loops: varbind after needs to be initialized */
2604 	for (i = 0; i < srl->ap_nsr; i++) {
2605 		if (i < axg->axg_nonrep ||
2606 		    axg->axg_type != AX_PDU_TYPE_GETBULK)
2607 			j = i;
2608 		else if (axg->axg_maxrep == 0)
2609 			break;
2610 		else
2611 			j = (axg->axg_maxrep * i) + axg->axg_nonrep;
2612 		bcopy(&(srl->ap_sr[i].asr_start),
2613 		    &(axg->axg_varbind[j].axv_vb.avb_oid),
2614 		    sizeof(srl->ap_sr[i].asr_start));
2615 		bcopy(&(srl->ap_sr[i].asr_start),
2616 		    &(axg->axg_varbind[j].axv_start),
2617 		    sizeof(srl->ap_sr[i].asr_start));
2618 		bcopy(&(srl->ap_sr[i].asr_stop),
2619 		    &(axg->axg_varbind[j].axv_end),
2620 		    sizeof(srl->ap_sr[i].asr_stop));
2621 		axg->axg_varbind[j].axv_initialized = 1;
2622 		axg->axg_varbind[j].axv_axg = axg;
2623 		axg->axg_varbind[j].axv_include =
2624 		    srl->ap_sr[i].asr_start.aoi_include;
2625 		if (j == 0)
2626 			fail |= agentx_strcat(&logmsg, " {");
2627 		else
2628 			fail |= agentx_strcat(&logmsg, ",{");
2629 		fail |= agentx_strcat(&logmsg,
2630 		    ax_oid2string(&(srl->ap_sr[i].asr_start)));
2631 		if (srl->ap_sr[i].asr_start.aoi_include)
2632 			fail |= agentx_strcat(&logmsg, " (inclusive)");
2633 		if (srl->ap_sr[i].asr_stop.aoi_idlen != 0) {
2634 			fail |= agentx_strcat(&logmsg, " - ");
2635 			fail |= agentx_strcat(&logmsg,
2636 			    ax_oid2string(&(srl->ap_sr[i].asr_stop)));
2637 		}
2638 		fail |= agentx_strcat(&logmsg, "}");
2639 		if (fail) {
2640 			agentx_log_axg_warn(axg, "Couldn't parse request");
2641 			free(logmsg);
2642 			agentx_get_free(axg);
2643 			agentx_reset(ax);
2644 			return;
2645 		}
2646 	}
2647 
2648 	agentx_log_axg_debug(axg, "%s:%s",
2649 	    ax_pdutype2string(axg->axg_type), logmsg);
2650 	free(logmsg);
2651 
2652 	for (i = 0; i < srl->ap_nsr; i++) {
2653 		if (i < axg->axg_nonrep ||
2654 		    axg->axg_type != AX_PDU_TYPE_GETBULK)
2655 			j = i;
2656 		else if (axg->axg_maxrep == 0)
2657 			break;
2658 		else
2659 			j = (axg->axg_maxrep * i) + axg->axg_nonrep;
2660 		agentx_varbind_start(&(axg->axg_varbind[j]));
2661 	}
2662 }
2663 
2664 static void
2665 agentx_get_finalize(struct agentx_get *axg)
2666 {
2667 	struct agentx_context *axc = axg->axg_axc;
2668 	struct agentx_session *axs;
2669 	struct agentx *ax;
2670 	size_t i, j, nvarbind = 0;
2671 	uint16_t error = 0, index = 0;
2672 	struct ax_varbind *vbl;
2673 	char *logmsg = NULL;
2674 	int fail = 0;
2675 
2676 	for (i = 0; i < axg->axg_nvarbind; i++) {
2677 		if (axg->axg_varbind[i].axv_initialized) {
2678 			if (axg->axg_varbind[i].axv_vb.avb_type == 0)
2679 				return;
2680 			nvarbind++;
2681 		}
2682 	}
2683 
2684 	if (axc == NULL) {
2685 		agentx_get_free(axg);
2686 		return;
2687 	}
2688 
2689 	axs = axc->axc_axs;
2690 	ax = axs->axs_ax;
2691 
2692 	if ((vbl = calloc(nvarbind, sizeof(*vbl))) == NULL) {
2693 		agentx_log_axg_warn(axg, "Couldn't parse request");
2694 		agentx_get_free(axg);
2695 		agentx_reset(ax);
2696 		return;
2697 	}
2698 	for (i = 0, j = 0; i < axg->axg_nvarbind; i++) {
2699 		if (axg->axg_varbind[i].axv_initialized) {
2700 			memcpy(&(vbl[j]), &(axg->axg_varbind[i].axv_vb),
2701 			    sizeof(*vbl));
2702 			if (error == 0 && axg->axg_varbind[i].axv_error !=
2703 			    AX_PDU_ERROR_NOERROR) {
2704 				error = axg->axg_varbind[i].axv_error;
2705 				index = j + 1;
2706 			}
2707 			if (j == 0)
2708 				fail |= agentx_strcat(&logmsg, " {");
2709 			else
2710 				fail |= agentx_strcat(&logmsg, ",{");
2711 			fail |= agentx_strcat(&logmsg,
2712 			    ax_varbind2string(&(vbl[j])));
2713 			if (axg->axg_varbind[i].axv_error !=
2714 			    AX_PDU_ERROR_NOERROR) {
2715 				fail |= agentx_strcat(&logmsg, "(");
2716 				fail |= agentx_strcat(&logmsg,
2717 				    ax_error2string(
2718 				    axg->axg_varbind[i].axv_error));
2719 				fail |= agentx_strcat(&logmsg, ")");
2720 			}
2721 			fail |= agentx_strcat(&logmsg, "}");
2722 			if (fail) {
2723 				agentx_log_axg_warn(axg,
2724 				    "Couldn't parse request");
2725 				free(logmsg);
2726 				agentx_get_free(axg);
2727 				return;
2728 			}
2729 			j++;
2730 		}
2731 	}
2732 	agentx_log_axg_debug(axg, "response:%s", logmsg);
2733 	free(logmsg);
2734 
2735 	if (ax_response(ax->ax_ax, axs->axs_id, axg->axg_transactionid,
2736 	    axg->axg_packetid, 0, error, index, vbl, nvarbind) == -1) {
2737 		agentx_log_axg_warn(axg, "Couldn't parse request");
2738 		agentx_reset(ax);
2739 	} else
2740 		agentx_wantwrite(ax, ax->ax_fd);
2741 	free(vbl);
2742 	agentx_get_free(axg);
2743 }
2744 
2745 void
2746 agentx_get_free(struct agentx_get *axg)
2747 {
2748 	struct agentx_varbind *axv;
2749 	struct agentx_object *axo;
2750 	struct agentx *ax;
2751 	struct agentx_varbind_index *index;
2752 	size_t i, j;
2753 
2754 	if (axg->axg_axc != NULL) {
2755 		ax = axg->axg_axc->axc_axs->axs_ax;
2756 		TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
2757 	}
2758 
2759 	for (i = 0; i < axg->axg_nvarbind; i++) {
2760 		axv = &(axg->axg_varbind[i]);
2761 		for (j = 0; axv->axv_axo != NULL &&
2762 		    j < axv->axv_axo->axo_indexlen; j++) {
2763 			axo = axv->axv_axo;
2764 			index = &(axv->axv_index[j]);
2765 			if (axo->axo_index[j]->axi_vb.avb_type ==
2766 			    AX_DATA_TYPE_OCTETSTRING ||
2767 			    axo->axo_index[j]->axi_vb.avb_type ==
2768 			    AX_DATA_TYPE_IPADDRESS)
2769 				free(index->axv_idata.avb_ostring.aos_string);
2770 		}
2771 		ax_varbind_free(&(axg->axg_varbind[i].axv_vb));
2772 	}
2773 
2774 	free(axg->axg_context.aos_string);
2775 	free(axg->axg_varbind);
2776 	free(axg);
2777 }
2778 
2779 static void
2780 agentx_varbind_start(struct agentx_varbind *axv)
2781 {
2782 	struct agentx_get *axg = axv->axv_axg;
2783 	struct agentx_context *axc = axg->axg_axc;
2784 	struct agentx_object *axo, axo_search;
2785 	struct agentx_varbind_index *index;
2786 	struct ax_oid *oid;
2787 	union ax_data *data;
2788 	struct in_addr *ipaddress;
2789 	unsigned char *ipbytes;
2790 	size_t i, j, k;
2791 	int overflow = 0, dynamic;
2792 
2793 #ifdef AX_DEBUG
2794 	if (!axv->axv_initialized)
2795 		agentx_log_axg_fatalx(axv->axv_axg,
2796 		    "%s: axv_initialized not set", __func__);
2797 #endif
2798 
2799 	if (axc == NULL) {
2800 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
2801 		return;
2802 	}
2803 
2804 	bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
2805 	    sizeof(axo_search.axo_oid));
2806 
2807 	do {
2808 		axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
2809 		if (axo_search.axo_oid.aoi_idlen > 0)
2810 			axo_search.axo_oid.aoi_idlen--;
2811 	} while (axo == NULL && axo_search.axo_oid.aoi_idlen > 0);
2812 	if (axo == NULL || axo->axo_cstate != AX_CSTATE_OPEN) {
2813 		axv->axv_include = 1;
2814 		if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
2815 			agentx_varbind_nosuchobject(axv);
2816 			return;
2817 		}
2818 		bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
2819 		    sizeof(axo_search.axo_oid));
2820 		axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
2821 getnext:
2822 		while (axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
2823 			axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
2824 		if (axo == NULL ||
2825 		    ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) >= 0) {
2826 			agentx_varbind_endofmibview(axv);
2827 			return;
2828 		}
2829 		bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
2830 		    sizeof(axo->axo_oid));
2831 	}
2832 	axv->axv_axo = axo;
2833 	axv->axv_indexlen = axo->axo_indexlen;
2834 	if (agentx_object_lock(axo) == -1) {
2835 		agentx_varbind_error_type(axv,
2836 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
2837 		return;
2838 	}
2839 
2840 	oid = &(axv->axv_vb.avb_oid);
2841 	if (axo->axo_indexlen == 0) {
2842 		if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
2843 			if (oid->aoi_idlen != axo->axo_oid.aoi_idlen + 1 ||
2844 			    oid->aoi_id[oid->aoi_idlen - 1] != 0) {
2845 				agentx_varbind_nosuchinstance(axv);
2846 				return;
2847 			}
2848 		} else {
2849 			if (oid->aoi_idlen == axo->axo_oid.aoi_idlen) {
2850 				oid->aoi_id[oid->aoi_idlen++] = 0;
2851 				axv->axv_include = 1;
2852 			} else {
2853 				axv->axv_axo = NULL;
2854 				agentx_object_unlock(axo);
2855 				axo = RB_NEXT(axc_objects, &(axc->axc_objects),
2856 				    axo);
2857 				goto getnext;
2858 			}
2859 		}
2860 		j = oid->aoi_idlen;
2861 	} else
2862 		j = axo->axo_oid.aoi_idlen;
2863 /*
2864  * We can't trust what the client gives us, so sometimes we need to map it to
2865  * index type.
2866  * - AX_PDU_TYPE_GET: we always return AX_DATA_TYPE_NOSUCHINSTANCE
2867  * - AX_PDU_TYPE_GETNEXT:
2868  *   - Missing OID digits to match indices or !dynamic indices
2869  *     (AX_DATA_TYPE_INTEGER) underflows will result in the following indices to
2870  *     be NUL-initialized and the request type will be set to
2871  *     AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
2872  *   - An overflow can happen on AX_DATA_TYPE_OCTETSTRING and
2873  *     AX_DATA_TYPE_IPADDRESS data, and AX_DATA_TYPE_OCTETSTRING and
2874  *     AX_DATA_TYPE_OID length. This results in request type being set to
2875  *     AGENTX_REQUEST_TYPE_GETNEXT and will set the index to its maximum
2876  *     value:
2877  *     - AX_DATA_TYPE_INTEGER: UINT32_MAX
2878  *     - AX_DATA_TYPE_OCTETSTRING: aos_slen = UINT32_MAX and
2879  *       aos_string = NULL
2880  *     - AX_DATA_TYPE_OID: aoi_idlen = UINT32_MAX and aoi_id[x] = UINT32_MAX
2881  *     - AX_DATA_TYPE_IPADDRESS: 255.255.255.255
2882  */
2883 	for (dynamic = 0, i = 0; i < axo->axo_indexlen; i++, j++) {
2884 		index = &(axv->axv_index[i]);
2885 		index->axv_axi = axo->axo_index[i];
2886 		data = &(index->axv_idata);
2887 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC)
2888 			dynamic = 1;
2889 		switch (axo->axo_index[i]->axi_vb.avb_type) {
2890 		case AX_DATA_TYPE_INTEGER:
2891 			if (index->axv_axi->axi_type != AXI_TYPE_DYNAMIC) {
2892 				index->axv_idata.avb_int32 =
2893 				    index->axv_axi->axi_vb.avb_data.avb_int32;
2894 				if (overflow == 0) {
2895 					if ((uint32_t)index->axv_idata.avb_int32 >
2896 					    oid->aoi_id[j])
2897 						overflow = -1;
2898 					else if ((uint32_t)index->axv_idata.avb_int32 <
2899 					    oid->aoi_id[j])
2900 						overflow = 1;
2901 				}
2902 			} else if (overflow == 1)
2903 				index->axv_idata.avb_int32 = INT32_MAX;
2904 			else if (j >= oid->aoi_idlen || overflow == -1)
2905 				index->axv_idata.avb_int32 = 0;
2906 			else {
2907 				if (oid->aoi_id[j] > INT32_MAX) {
2908 					index->axv_idata.avb_int32 = INT32_MAX;
2909 					overflow = 1;
2910 				} else
2911 					index->axv_idata.avb_int32 =
2912 					    oid->aoi_id[j];
2913 			}
2914 			break;
2915 		case AX_DATA_TYPE_OCTETSTRING:
2916 			if (overflow == 1) {
2917 				data->avb_ostring.aos_slen = UINT32_MAX;
2918 				data->avb_ostring.aos_string = NULL;
2919 				continue;
2920 			} else if (j >= oid->aoi_idlen || overflow == -1) {
2921 				data->avb_ostring.aos_slen = 0;
2922 				data->avb_ostring.aos_string = NULL;
2923 				continue;
2924 			}
2925 			if (agentx_object_implied(axo, index->axv_axi))
2926 				data->avb_ostring.aos_slen = oid->aoi_idlen - j;
2927 			else {
2928 				data->avb_ostring.aos_slen = oid->aoi_id[j++];
2929 				if (data->avb_ostring.aos_slen >=
2930 				    AGENTX_OID_MAX_LEN - j) {
2931 					data->avb_ostring.aos_slen = UINT32_MAX;
2932 					overflow = 1;
2933 				}
2934 			}
2935 			if (data->avb_ostring.aos_slen == UINT32_MAX ||
2936 			    data->avb_ostring.aos_slen == 0) {
2937 				data->avb_ostring.aos_string = NULL;
2938 				continue;
2939 			}
2940 			data->avb_ostring.aos_string =
2941 			    malloc(data->avb_ostring.aos_slen + 1);
2942 			if (data->avb_ostring.aos_string == NULL) {
2943 				agentx_log_axg_warn(axg,
2944 				    "Failed to bind string index");
2945 				agentx_varbind_error_type(axv,
2946 				    AX_PDU_ERROR_PROCESSINGERROR, 1);
2947 				return;
2948 			}
2949 			for (k = 0; k < data->avb_ostring.aos_slen; k++, j++) {
2950 				if (j < oid->aoi_idlen && oid->aoi_id[j] > 0xff)
2951 					overflow = 1;
2952 				if (overflow == 1)
2953 					data->avb_ostring.aos_string[k] = 0xff;
2954 				else if (j >= oid->aoi_idlen || overflow == -1)
2955 					data->avb_ostring.aos_string[k] = '\0';
2956 				else
2957 					data->avb_ostring.aos_string[k] =
2958 					    oid->aoi_id[j];
2959 			}
2960 			data->avb_ostring.aos_string[k] = '\0';
2961 			j--;
2962 			break;
2963 		case AX_DATA_TYPE_OID:
2964 			if (overflow == 1) {
2965 				data->avb_oid.aoi_idlen = UINT32_MAX;
2966 				continue;
2967 			} else if (j >= oid->aoi_idlen || overflow == -1) {
2968 				data->avb_oid.aoi_idlen = 0;
2969 				continue;
2970 			}
2971 			if (agentx_object_implied(axo, index->axv_axi))
2972 				data->avb_oid.aoi_idlen = oid->aoi_idlen - j;
2973 			else {
2974 				data->avb_oid.aoi_idlen = oid->aoi_id[j++];
2975 				if (data->avb_oid.aoi_idlen >=
2976 				    AGENTX_OID_MAX_LEN - j) {
2977 					data->avb_oid.aoi_idlen = UINT32_MAX;
2978 					overflow = 1;
2979 				}
2980 			}
2981 			if (data->avb_oid.aoi_idlen == UINT32_MAX ||
2982 			    data->avb_oid.aoi_idlen == 0)
2983 				continue;
2984 			for (k = 0; k < data->avb_oid.aoi_idlen; k++, j++) {
2985 				if (overflow == 1)
2986 					data->avb_oid.aoi_id[k] = UINT32_MAX;
2987 				else if (j >= oid->aoi_idlen || overflow == -1)
2988 					data->avb_oid.aoi_id[k] = 0;
2989 				else
2990 					data->avb_oid.aoi_id[k] =
2991 					    oid->aoi_id[j];
2992 			}
2993 			j--;
2994 			break;
2995 		case AX_DATA_TYPE_IPADDRESS:
2996 			ipaddress = malloc(sizeof(*ipaddress));
2997 			if (ipaddress == NULL) {
2998 				agentx_log_axg_warn(axg,
2999 				    "Failed to bind ipaddress index");
3000 				agentx_varbind_error_type(axv,
3001 				    AX_PDU_ERROR_PROCESSINGERROR, 1);
3002 				return;
3003 			}
3004 			ipbytes = (unsigned char *)ipaddress;
3005 			for (k = 0; k < 4; k++, j++) {
3006 				if (j < oid->aoi_idlen && oid->aoi_id[j] > 255)
3007 					overflow = 1;
3008 				if (overflow == 1)
3009 					ipbytes[k] = 255;
3010 				else if (j >= oid->aoi_idlen || overflow == -1)
3011 					ipbytes[k] = 0;
3012 				else
3013 					ipbytes[k] = oid->aoi_id[j];
3014 			}
3015 			j--;
3016 			data->avb_ostring.aos_slen = sizeof(*ipaddress);
3017 			data->avb_ostring.aos_string =
3018 			    (unsigned char *)ipaddress;
3019 			break;
3020 		default:
3021 #ifdef AX_DEBUG
3022 			agentx_log_axg_fatalx(axg,
3023 			    "%s: unexpected index type", __func__);
3024 #else
3025 			agentx_log_axg_warnx(axg,
3026 			    "%s: unexpected index type", __func__);
3027 			agentx_varbind_error_type(axv,
3028 			    AX_PDU_ERROR_PROCESSINGERROR, 1);
3029 			return;
3030 #endif
3031 		}
3032 	}
3033 	if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
3034 		if (j != oid->aoi_idlen || overflow) {
3035 			agentx_varbind_nosuchinstance(axv);
3036 			return;
3037 		}
3038 	}
3039 
3040 	if (overflow == 1) {
3041 		axv->axv_include = 0;
3042 	} else if (overflow == -1) {
3043 		axv->axv_include = 1;
3044 	} else if (j < oid->aoi_idlen)
3045 		axv->axv_include = 0;
3046 	else if (j > oid->aoi_idlen)
3047 		axv->axv_include = 1;
3048 	if (agentx_varbind_request(axv) == AGENTX_REQUEST_TYPE_GETNEXT &&
3049 	    !dynamic) {
3050 		agentx_varbind_endofmibview(axv);
3051 		return;
3052 	}
3053 
3054 	axo->axo_get(axv);
3055 }
3056 
3057 void
3058 agentx_varbind_integer(struct agentx_varbind *axv, int32_t value)
3059 {
3060 	axv->axv_vb.avb_type = AX_DATA_TYPE_INTEGER;
3061 	axv->axv_vb.avb_data.avb_int32 = value;
3062 
3063 	agentx_varbind_finalize(axv);
3064 }
3065 
3066 void
3067 agentx_varbind_string(struct agentx_varbind *axv, const char *value)
3068 {
3069 	agentx_varbind_nstring(axv, (const unsigned char *)value,
3070 	    strlen(value));
3071 }
3072 
3073 void
3074 agentx_varbind_nstring(struct agentx_varbind *axv,
3075     const unsigned char *value, size_t slen)
3076 {
3077 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(slen);
3078 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
3079 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
3080 		agentx_varbind_error_type(axv,
3081 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
3082 		return;
3083 	}
3084 	axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
3085 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, slen);
3086 	axv->axv_vb.avb_data.avb_ostring.aos_slen = slen;
3087 
3088 	agentx_varbind_finalize(axv);
3089 }
3090 
3091 void
3092 agentx_varbind_printf(struct agentx_varbind *axv, const char *fmt, ...)
3093 {
3094 	va_list ap;
3095 	int r;
3096 
3097 	axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
3098 	va_start(ap, fmt);
3099 	r = vasprintf((char **)&(axv->axv_vb.avb_data.avb_ostring.aos_string),
3100 	    fmt, ap);
3101 	va_end(ap);
3102 	if (r == -1) {
3103 		axv->axv_vb.avb_data.avb_ostring.aos_string = NULL;
3104 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
3105 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
3106 		return;
3107 	}
3108 	axv->axv_vb.avb_data.avb_ostring.aos_slen = r;
3109 
3110 	agentx_varbind_finalize(axv);
3111 }
3112 
3113 void
3114 agentx_varbind_null(struct agentx_varbind *axv)
3115 {
3116 	axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
3117 
3118 	agentx_varbind_finalize(axv);
3119 }
3120 
3121 void
3122 agentx_varbind_oid(struct agentx_varbind *axv, const uint32_t oid[],
3123     size_t oidlen)
3124 {
3125 	const char *errstr;
3126 
3127 	axv->axv_vb.avb_type = AX_DATA_TYPE_OID;
3128 
3129 	if (agentx_oidfill(&(axv->axv_vb.avb_data.avb_oid),
3130 	    oid, oidlen, &errstr) == -1) {
3131 #ifdef AX_DEBUG
3132 		agentx_log_axg_fatalx(axv->axv_axg, "%s: %s", __func__, errstr);
3133 #else
3134 		agentx_log_axg_warnx(axv->axv_axg, "%s: %s", __func__, errstr);
3135 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
3136 		return;
3137 #endif
3138 	}
3139 
3140 	agentx_varbind_finalize(axv);
3141 }
3142 
3143 void
3144 agentx_varbind_object(struct agentx_varbind *axv,
3145     struct agentx_object *axo)
3146 {
3147 	agentx_varbind_oid(axv, axo->axo_oid.aoi_id,
3148 	    axo->axo_oid.aoi_idlen);
3149 }
3150 
3151 void
3152 agentx_varbind_index(struct agentx_varbind *axv,
3153     struct agentx_index *axi)
3154 {
3155 	agentx_varbind_oid(axv, axi->axi_vb.avb_oid.aoi_id,
3156 	    axi->axi_vb.avb_oid.aoi_idlen);
3157 }
3158 
3159 
3160 void
3161 agentx_varbind_ipaddress(struct agentx_varbind *axv,
3162     const struct in_addr *value)
3163 {
3164 	axv->axv_vb.avb_type = AX_DATA_TYPE_IPADDRESS;
3165 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(4);
3166 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
3167 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind ipaddress");
3168 		agentx_varbind_error_type(axv,
3169 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
3170 		return;
3171 	}
3172 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, 4);
3173 	axv->axv_vb.avb_data.avb_ostring.aos_slen = 4;
3174 
3175 	agentx_varbind_finalize(axv);
3176 }
3177 
3178 void
3179 agentx_varbind_counter32(struct agentx_varbind *axv, uint32_t value)
3180 {
3181 	axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER32;
3182 	axv->axv_vb.avb_data.avb_uint32 = value;
3183 
3184 	agentx_varbind_finalize(axv);
3185 }
3186 
3187 void
3188 agentx_varbind_gauge32(struct agentx_varbind *axv, uint32_t value)
3189 {
3190 	axv->axv_vb.avb_type = AX_DATA_TYPE_GAUGE32;
3191 	axv->axv_vb.avb_data.avb_uint32 = value;
3192 
3193 	agentx_varbind_finalize(axv);
3194 }
3195 
3196 void
3197 agentx_varbind_unsigned32(struct agentx_varbind *axv, uint32_t value)
3198 {
3199 	agentx_varbind_gauge32(axv, value);
3200 }
3201 
3202 void
3203 agentx_varbind_timeticks(struct agentx_varbind *axv, uint32_t value)
3204 {
3205 	axv->axv_vb.avb_type = AX_DATA_TYPE_TIMETICKS;
3206 	axv->axv_vb.avb_data.avb_uint32 = value;
3207 
3208 	agentx_varbind_finalize(axv);
3209 }
3210 
3211 void
3212 agentx_varbind_opaque(struct agentx_varbind *axv, const char *string,
3213     size_t strlen)
3214 {
3215 	axv->axv_vb.avb_type = AX_DATA_TYPE_OPAQUE;
3216 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(strlen);
3217 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
3218 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind opaque");
3219 		agentx_varbind_error_type(axv,
3220 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
3221 		return;
3222 	}
3223 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, string, strlen);
3224 	axv->axv_vb.avb_data.avb_ostring.aos_slen = strlen;
3225 
3226 	agentx_varbind_finalize(axv);
3227 }
3228 
3229 void
3230 agentx_varbind_counter64(struct agentx_varbind *axv, uint64_t value)
3231 {
3232 	axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER64;
3233 	axv->axv_vb.avb_data.avb_uint64 = value;
3234 
3235 	agentx_varbind_finalize(axv);
3236 }
3237 
3238 void
3239 agentx_varbind_notfound(struct agentx_varbind *axv)
3240 {
3241 	if (axv->axv_indexlen == 0) {
3242 #ifdef AX_DEBUG
3243 		agentx_log_axg_fatalx(axv->axv_axg, "%s invalid call",
3244 		    __func__);
3245 #else
3246 		agentx_log_axg_warnx(axv->axv_axg, "%s invalid call",
3247 		    __func__);
3248 		agentx_varbind_error_type(axv,
3249 		    AX_PDU_ERROR_GENERR, 1);
3250 #endif
3251 	} else if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
3252 		agentx_varbind_nosuchinstance(axv);
3253 	else
3254 		agentx_varbind_endofmibview(axv);
3255 }
3256 
3257 void
3258 agentx_varbind_error(struct agentx_varbind *axv)
3259 {
3260 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 1);
3261 }
3262 
3263 static void
3264 agentx_varbind_error_type(struct agentx_varbind *axv,
3265     enum ax_pdu_error error, int done)
3266 {
3267 	if (axv->axv_error == AX_PDU_ERROR_NOERROR) {
3268 		axv->axv_error = error;
3269 	}
3270 
3271 	if (done) {
3272 		axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
3273 
3274 		agentx_varbind_finalize(axv);
3275 	}
3276 }
3277 
3278 static void
3279 agentx_varbind_finalize(struct agentx_varbind *axv)
3280 {
3281 	struct agentx_get *axg = axv->axv_axg;
3282 	struct ax_oid oid;
3283 	union ax_data *data;
3284 	size_t i, j;
3285 	int cmp;
3286 
3287 	if (axv->axv_error != AX_PDU_ERROR_NOERROR) {
3288 		bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3289 		    sizeof(axv->axv_start));
3290 		goto done;
3291 	}
3292 	bcopy(&(axv->axv_axo->axo_oid), &oid, sizeof(oid));
3293 	if (axv->axv_indexlen == 0)
3294 		ax_oid_add(&oid, 0);
3295 	for (i = 0; i < axv->axv_indexlen; i++) {
3296 		data = &(axv->axv_index[i].axv_idata);
3297 		switch (axv->axv_index[i].axv_axi->axi_vb.avb_type) {
3298 		case AX_DATA_TYPE_INTEGER:
3299 			if (ax_oid_add(&oid, data->avb_int32) == -1)
3300 				goto fail;
3301 			break;
3302 		case AX_DATA_TYPE_OCTETSTRING:
3303 			if (!agentx_object_implied(axv->axv_axo,
3304 			    axv->axv_index[i].axv_axi)) {
3305 				if (ax_oid_add(&oid,
3306 				    data->avb_ostring.aos_slen) == -1)
3307 					goto fail;
3308 			}
3309 			for (j = 0; j < data->avb_ostring.aos_slen; j++) {
3310 				if (ax_oid_add(&oid,
3311 				    (uint8_t)data->avb_ostring.aos_string[j]) ==
3312 				    -1)
3313 					goto fail;
3314 			}
3315 			break;
3316 		case AX_DATA_TYPE_OID:
3317 			if (!agentx_object_implied(axv->axv_axo,
3318 			    axv->axv_index[i].axv_axi)) {
3319 				if (ax_oid_add(&oid,
3320 				    data->avb_oid.aoi_idlen) == -1)
3321 					goto fail;
3322 			}
3323 			for (j = 0; j < data->avb_oid.aoi_idlen; j++) {
3324 				if (ax_oid_add(&oid,
3325 				    data->avb_oid.aoi_id[j]) == -1)
3326 					goto fail;
3327 			}
3328 			break;
3329 		case AX_DATA_TYPE_IPADDRESS:
3330 			for (j = 0; j < 4; j++) {
3331 				if (ax_oid_add(&oid,
3332 				    data->avb_ostring.aos_string == NULL ? 0 :
3333 				    (uint8_t)data->avb_ostring.aos_string[j]) ==
3334 				    -1)
3335 					goto fail;
3336 			}
3337 			break;
3338 		default:
3339 #ifdef AX_DEBUG
3340 			agentx_log_axg_fatalx(axg,
3341 			    "%s: unsupported index type", __func__);
3342 #else
3343 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3344 			    sizeof(axv->axv_start));
3345 			axv->axv_error = AX_PDU_ERROR_PROCESSINGERROR;
3346 			agentx_object_unlock(axv->axv_axo);
3347 			agentx_get_finalize(axv->axv_axg);
3348 			return;
3349 #endif
3350 		}
3351 	}
3352 	cmp = ax_oid_cmp(&oid, &(axv->axv_vb.avb_oid));
3353 	switch (agentx_varbind_request(axv)) {
3354 	case AGENTX_REQUEST_TYPE_GET:
3355 		if (cmp != 0) {
3356 #ifdef AX_DEBUG
3357 			agentx_log_axg_fatalx(axg, "index changed");
3358 #else
3359 			agentx_log_axg_warnx(axg, "index changed");
3360 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3361 			    sizeof(axv->axv_start));
3362 			axv->axv_error = AX_PDU_ERROR_GENERR;
3363 			break;
3364 #endif
3365 		}
3366 		break;
3367 	case AGENTX_REQUEST_TYPE_GETNEXT:
3368 		if (cmp <= 0) {
3369 #ifdef AX_DEBUG
3370 			agentx_log_axg_fatalx(axg, "indices not incremented");
3371 #else
3372 			agentx_log_axg_warnx(axg, "indices not incremented");
3373 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3374 			    sizeof(axv->axv_start));
3375 			axv->axv_error = AX_PDU_ERROR_GENERR;
3376 			break;
3377 #endif
3378 		}
3379 		/* FALLTHROUGH */
3380 	case AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE:
3381 		if (cmp < 0) {
3382 #ifdef AX_DEBUG
3383 			agentx_log_axg_fatalx(axg, "index decremented");
3384 #else
3385 			agentx_log_axg_warnx(axg, "index decremented");
3386 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3387 			    sizeof(axv->axv_start));
3388 			axv->axv_error = AX_PDU_ERROR_GENERR;
3389 			break;
3390 #endif
3391 		}
3392 		if (axv->axv_end.aoi_idlen != 0 &&
3393 		    ax_oid_cmp(&oid, &(axv->axv_end)) >= 0) {
3394 			agentx_varbind_endofmibview(axv);
3395 			return;
3396 		}
3397 		bcopy(&oid, &(axv->axv_vb.avb_oid), sizeof(oid));
3398 	}
3399 done:
3400 	agentx_object_unlock(axv->axv_axo);
3401 	agentx_get_finalize(axv->axv_axg);
3402 	return;
3403 
3404 fail:
3405 	agentx_log_axg_warnx(axg, "oid too large");
3406 	bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3407 	    sizeof(axv->axv_start));
3408 	axv->axv_error = AX_PDU_ERROR_GENERR;
3409 	agentx_object_unlock(axv->axv_axo);
3410 	agentx_get_finalize(axv->axv_axg);
3411 }
3412 
3413 static void
3414 agentx_varbind_nosuchobject(struct agentx_varbind *axv)
3415 {
3416 	axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHOBJECT;
3417 
3418 	if (axv->axv_axo != NULL)
3419 		agentx_object_unlock(axv->axv_axo);
3420 	agentx_get_finalize(axv->axv_axg);
3421 }
3422 
3423 static void
3424 agentx_varbind_nosuchinstance(struct agentx_varbind *axv)
3425 {
3426 	axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHINSTANCE;
3427 
3428 	if (axv->axv_axo != NULL)
3429 		agentx_object_unlock(axv->axv_axo);
3430 	agentx_get_finalize(axv->axv_axg);
3431 }
3432 
3433 static void
3434 agentx_varbind_endofmibview(struct agentx_varbind *axv)
3435 {
3436 	struct agentx_object *axo;
3437 	struct ax_varbind *vb;
3438 	struct agentx_varbind_index *index;
3439 	size_t i;
3440 
3441 #ifdef AX_DEBUG
3442 	if (axv->axv_axg->axg_type != AX_PDU_TYPE_GETNEXT &&
3443 	    axv->axv_axg->axg_type != AX_PDU_TYPE_GETBULK)
3444 		agentx_log_axg_fatalx(axv->axv_axg,
3445 		    "%s: invalid request type", __func__);
3446 #endif
3447 
3448 	if (axv->axv_axo != NULL &&
3449 	    (axo = RB_NEXT(axc_objects, &(axc->axc_objects),
3450 	    axv->axv_axo)) != NULL &&
3451 	    ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) < 0) {
3452 		bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
3453 		    sizeof(axo->axo_oid));
3454 		axv->axv_include = 1;
3455 		for (i = 0; i < axv->axv_indexlen; i++) {
3456 			index = &(axv->axv_index[i]);
3457 			vb = &(index->axv_axi->axi_vb);
3458 			if (vb->avb_type == AX_DATA_TYPE_OCTETSTRING ||
3459 			    vb->avb_type == AX_DATA_TYPE_IPADDRESS)
3460 				free(index->axv_idata.avb_ostring.aos_string);
3461 		}
3462 		bzero(&(axv->axv_index), sizeof(axv->axv_index));
3463 		agentx_object_unlock(axv->axv_axo);
3464 		agentx_varbind_start(axv);
3465 		return;
3466 	}
3467 
3468 	bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3469 	    sizeof(axv->axv_start));
3470 	axv->axv_vb.avb_type = AX_DATA_TYPE_ENDOFMIBVIEW;
3471 
3472 	if (axv->axv_axo != NULL)
3473 		agentx_object_unlock(axv->axv_axo);
3474 	agentx_get_finalize(axv->axv_axg);
3475 }
3476 
3477 enum agentx_request_type
3478 agentx_varbind_request(struct agentx_varbind *axv)
3479 {
3480 	if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
3481 		return AGENTX_REQUEST_TYPE_GET;
3482 	if (axv->axv_include)
3483 		return AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE;
3484 	return AGENTX_REQUEST_TYPE_GETNEXT;
3485 }
3486 
3487 struct agentx_object *
3488 agentx_varbind_get_object(struct agentx_varbind *axv)
3489 {
3490 	return axv->axv_axo;
3491 }
3492 
3493 int32_t
3494 agentx_varbind_get_index_integer(struct agentx_varbind *axv,
3495     struct agentx_index *axi)
3496 {
3497 	size_t i;
3498 
3499 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
3500 #ifdef AX_DEBUG
3501 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3502 #else
3503 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3504 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3505 		return 0;
3506 #endif
3507 	}
3508 
3509 	for (i = 0; i < axv->axv_indexlen; i++) {
3510 		if (axv->axv_index[i].axv_axi == axi)
3511 			return axv->axv_index[i].axv_idata.avb_int32;
3512 	}
3513 #ifdef AX_DEBUG
3514 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3515 #else
3516 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3517 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3518 	return 0;
3519 #endif
3520 }
3521 
3522 const unsigned char *
3523 agentx_varbind_get_index_string(struct agentx_varbind *axv,
3524     struct agentx_index *axi, size_t *slen, int *implied)
3525 {
3526 	struct agentx_varbind_index *index;
3527 	size_t i;
3528 
3529 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
3530 #ifdef AX_DEBUG
3531 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3532 #else
3533 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3534 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3535 		*slen = 0;
3536 		*implied = 0;
3537 		return NULL;
3538 #endif
3539 	}
3540 
3541 	for (i = 0; i < axv->axv_indexlen; i++) {
3542 		if (axv->axv_index[i].axv_axi == axi) {
3543 			index = &(axv->axv_index[i]);
3544 			*slen = index->axv_idata.avb_ostring.aos_slen;
3545 			*implied = agentx_object_implied(axv->axv_axo, axi);
3546 			return index->axv_idata.avb_ostring.aos_string;
3547 		}
3548 	}
3549 
3550 #ifdef AX_DEBUG
3551 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3552 #else
3553 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3554 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3555 	*slen = 0;
3556 	*implied = 0;
3557 	return NULL;
3558 #endif
3559 }
3560 
3561 const uint32_t *
3562 agentx_varbind_get_index_oid(struct agentx_varbind *axv,
3563     struct agentx_index *axi, size_t *oidlen, int *implied)
3564 {
3565 	struct agentx_varbind_index *index;
3566 	size_t i;
3567 
3568 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
3569 #ifdef AX_DEBUG
3570 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3571 #else
3572 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3573 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3574 		*oidlen = 0;
3575 		*implied = 0;
3576 		return NULL;
3577 #endif
3578 	}
3579 
3580 	for (i = 0; i < axv->axv_indexlen; i++) {
3581 		if (axv->axv_index[i].axv_axi == axi) {
3582 			index = &(axv->axv_index[i]);
3583 			*oidlen = index->axv_idata.avb_oid.aoi_idlen;
3584 			*implied = agentx_object_implied(axv->axv_axo, axi);
3585 			return index->axv_idata.avb_oid.aoi_id;
3586 		}
3587 	}
3588 
3589 #ifdef AX_DEBUG
3590 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3591 #else
3592 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3593 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3594 	*oidlen = 0;
3595 	*implied = 0;
3596 	return NULL;
3597 #endif
3598 }
3599 
3600 const struct in_addr *
3601 agentx_varbind_get_index_ipaddress(struct agentx_varbind *axv,
3602     struct agentx_index *axi)
3603 {
3604 	static struct in_addr nuladdr = {0};
3605 	struct agentx_varbind_index *index;
3606 	size_t i;
3607 
3608 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
3609 #ifdef AX_DEBUG
3610 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3611 #else
3612 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3613 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3614 		return NULL;
3615 #endif
3616 	}
3617 
3618 	for (i = 0; i < axv->axv_indexlen; i++) {
3619 		if (axv->axv_index[i].axv_axi == axi) {
3620 			index = &(axv->axv_index[i]);
3621 			if (index->axv_idata.avb_ostring.aos_string == NULL)
3622 				return &nuladdr;
3623 			return (struct in_addr *)
3624 			    index->axv_idata.avb_ostring.aos_string;
3625 		}
3626 	}
3627 
3628 #ifdef AX_DEBUG
3629 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3630 #else
3631 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3632 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3633 	return NULL;
3634 #endif
3635 }
3636 
3637 void
3638 agentx_varbind_set_index_integer(struct agentx_varbind *axv,
3639     struct agentx_index *axi, int32_t value)
3640 {
3641 	size_t i;
3642 
3643 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
3644 #ifdef AX_DEBUG
3645 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3646 #else
3647 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3648 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3649 		return;
3650 #endif
3651 	}
3652 
3653 	if (value < 0) {
3654 #ifdef AX_DEBUG
3655 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index value");
3656 #else
3657 		agentx_log_axg_warnx(axv->axv_axg, "invalid index value");
3658 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3659 		return;
3660 #endif
3661 	}
3662 
3663 	for (i = 0; i < axv->axv_indexlen; i++) {
3664 		if (axv->axv_index[i].axv_axi == axi) {
3665 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3666 			    axv->axv_index[i].axv_idata.avb_int32 != value) {
3667 #ifdef AX_DEBUG
3668 				agentx_log_axg_fatalx(axv->axv_axg,
3669 				    "can't change index on GET");
3670 #else
3671 				agentx_log_axg_warnx(axv->axv_axg,
3672 				    "can't change index on GET");
3673 				agentx_varbind_error_type(axv,
3674 				    AX_PDU_ERROR_GENERR, 0);
3675 				return;
3676 #endif
3677 			}
3678 			axv->axv_index[i].axv_idata.avb_int32 = value;
3679 			return;
3680 		}
3681 	}
3682 #ifdef AX_DEBUG
3683 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3684 #else
3685 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3686 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3687 #endif
3688 }
3689 
3690 void
3691 agentx_varbind_set_index_string(struct agentx_varbind *axv,
3692     struct agentx_index *axi, const char *value)
3693 {
3694 	agentx_varbind_set_index_nstring(axv, axi,
3695 	    (const unsigned char *)value, strlen(value));
3696 }
3697 
3698 void
3699 agentx_varbind_set_index_nstring(struct agentx_varbind *axv,
3700     struct agentx_index *axi, const unsigned char *value, size_t slen)
3701 {
3702 	struct ax_ostring *curvalue;
3703 	unsigned char *nstring;
3704 	size_t i;
3705 
3706 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
3707 #ifdef AX_DEBUG
3708 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3709 #else
3710 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3711 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3712 		return;
3713 #endif
3714 	}
3715 
3716 	for (i = 0; i < axv->axv_indexlen; i++) {
3717 		if (axv->axv_index[i].axv_axi == axi) {
3718 			if (axi->axi_vb.avb_data.avb_ostring.aos_slen != 0 &&
3719 			    axi->axi_vb.avb_data.avb_ostring.aos_slen != slen) {
3720 #ifdef AX_DEBUG
3721 				agentx_log_axg_fatalx(axv->axv_axg,
3722 				    "invalid string length on explicit length "
3723 				    "string");
3724 #else
3725 				agentx_log_axg_warnx(axv->axv_axg,
3726 				    "invalid string length on explicit length "
3727 				    "string");
3728 				agentx_varbind_error_type(axv,
3729 				    AX_PDU_ERROR_GENERR, 0);
3730 				return;
3731 #endif
3732 			}
3733 			curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
3734 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3735 			    (curvalue->aos_slen != slen ||
3736 			    memcmp(curvalue->aos_string, value, slen) != 0)) {
3737 #ifdef AX_DEBUG
3738 				agentx_log_axg_fatalx(axv->axv_axg,
3739 				    "can't change index on GET");
3740 #else
3741 				agentx_log_axg_warnx(axv->axv_axg,
3742 				    "can't change index on GET");
3743 				agentx_varbind_error_type(axv,
3744 				    AX_PDU_ERROR_GENERR, 0);
3745 				return;
3746 #endif
3747 			}
3748 			if ((nstring = recallocarray(curvalue->aos_string,
3749 			    curvalue->aos_slen + 1, slen + 1, 1)) == NULL) {
3750 				agentx_log_axg_warn(axv->axv_axg,
3751 				    "Failed to bind string index");
3752 				agentx_varbind_error_type(axv,
3753 				    AX_PDU_ERROR_PROCESSINGERROR, 0);
3754 				return;
3755 			}
3756 			curvalue->aos_string = nstring;
3757 			memcpy(nstring, value, slen);
3758 			curvalue->aos_slen = slen;
3759 			return;
3760 		}
3761 	}
3762 #ifdef AX_DEBUG
3763 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3764 #else
3765 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3766 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3767 #endif
3768 }
3769 
3770 void
3771 agentx_varbind_set_index_oid(struct agentx_varbind *axv,
3772     struct agentx_index *axi, const uint32_t *value, size_t oidlen)
3773 {
3774 	struct ax_oid *curvalue, oid;
3775 	const char *errstr;
3776 	size_t i;
3777 
3778 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
3779 #ifdef AX_DEBUG
3780 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3781 #else
3782 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3783 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3784 		return;
3785 #endif
3786 	}
3787 
3788 	for (i = 0; i < axv->axv_indexlen; i++) {
3789 		if (axv->axv_index[i].axv_axi == axi) {
3790 			if (axi->axi_vb.avb_data.avb_oid.aoi_idlen != 0 &&
3791 			    axi->axi_vb.avb_data.avb_oid.aoi_idlen != oidlen) {
3792 #ifdef AX_DEBUG
3793 				agentx_log_axg_fatalx(axv->axv_axg,
3794 				    "invalid oid length on explicit length "
3795 				    "oid");
3796 #else
3797 				agentx_log_axg_warnx(axv->axv_axg,
3798 				    "invalid oid length on explicit length "
3799 				    "oid");
3800 				agentx_varbind_error_type(axv,
3801 				    AX_PDU_ERROR_GENERR, 0);
3802 				return;
3803 #endif
3804 			}
3805 			curvalue = &(axv->axv_index[i].axv_idata.avb_oid);
3806 			if (agentx_oidfill(&oid, value,
3807 			    oidlen, &errstr) == -1) {
3808 #ifdef AX_DEBUG
3809 				agentx_log_axg_fatalx(axv->axv_axg, "%s: %s",
3810 				    __func__, errstr);
3811 #else
3812 				agentx_log_axg_warnx(axv->axv_axg, "%s: %s",
3813 				     __func__, errstr);
3814 				agentx_varbind_error_type(axv,
3815 				     AX_PDU_ERROR_PROCESSINGERROR, 1);
3816 				return;
3817 #endif
3818 			}
3819 
3820 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3821 			    ax_oid_cmp(&oid, curvalue) != 0) {
3822 #ifdef AX_DEBUG
3823 				agentx_log_axg_fatalx(axv->axv_axg,
3824 				    "can't change index on GET");
3825 #else
3826 				agentx_log_axg_warnx(axv->axv_axg,
3827 				    "can't change index on GET");
3828 				agentx_varbind_error_type(axv,
3829 				    AX_PDU_ERROR_GENERR, 0);
3830 				return;
3831 #endif
3832 			}
3833 
3834 			*curvalue = oid;
3835 			return;
3836 		}
3837 	}
3838 #ifdef AX_DEBUG
3839 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3840 #else
3841 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3842 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3843 #endif
3844 }
3845 
3846 void
3847 agentx_varbind_set_index_object(struct agentx_varbind *axv,
3848     struct agentx_index *axi, struct agentx_object *axo)
3849 {
3850 	agentx_varbind_set_index_oid(axv, axi, axo->axo_oid.aoi_id,
3851 	    axo->axo_oid.aoi_idlen);
3852 }
3853 
3854 void
3855 agentx_varbind_set_index_ipaddress(struct agentx_varbind *axv,
3856     struct agentx_index *axi, const struct in_addr *addr)
3857 {
3858 	struct ax_ostring *curvalue;
3859 	size_t i;
3860 
3861 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
3862 #ifdef AX_DEBUG
3863 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3864 #else
3865 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3866 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3867 		return;
3868 #endif
3869 	}
3870 
3871 	for (i = 0; i < axv->axv_indexlen; i++) {
3872 		if (axv->axv_index[i].axv_axi == axi) {
3873 			curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
3874 			if (curvalue->aos_string == NULL)
3875 				curvalue->aos_string = calloc(1, sizeof(*addr));
3876 			if (curvalue->aos_string == NULL) {
3877 				agentx_log_axg_warn(axv->axv_axg,
3878 				    "Failed to bind ipaddress index");
3879 				agentx_varbind_error_type(axv,
3880 				    AX_PDU_ERROR_PROCESSINGERROR, 0);
3881 				return;
3882 			}
3883 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3884 			    memcmp(addr, curvalue->aos_string,
3885 			    sizeof(*addr)) != 0) {
3886 #ifdef AX_DEBUG
3887 				agentx_log_axg_fatalx(axv->axv_axg,
3888 				    "can't change index on GET");
3889 #else
3890 				agentx_log_axg_warnx(axv->axv_axg,
3891 				    "can't change index on GET");
3892 				agentx_varbind_error_type(axv,
3893 				    AX_PDU_ERROR_GENERR, 0);
3894 				return;
3895 #endif
3896 			}
3897 			bcopy(addr, curvalue->aos_string, sizeof(*addr));
3898 			return;
3899 		}
3900 	}
3901 #ifdef AX_DEBUG
3902 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3903 #else
3904 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3905 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3906 #endif
3907 }
3908 
3909 static int
3910 agentx_request(struct agentx *ax, uint32_t packetid,
3911     int (*cb)(struct ax_pdu *, void *), void *cookie)
3912 {
3913 	struct agentx_request *axr;
3914 
3915 #ifdef AX_DEBUG
3916 	if (ax->ax_ax->ax_wblen == 0)
3917 		agentx_log_ax_fatalx(ax, "%s: no data to be written",
3918 		    __func__);
3919 #endif
3920 
3921 	if ((axr = calloc(1, sizeof(*axr))) == NULL) {
3922 		agentx_log_ax_warn(ax, "couldn't create request context");
3923 		agentx_reset(ax);
3924 		return -1;
3925 	}
3926 
3927 	axr->axr_packetid = packetid;
3928 	axr->axr_cb = cb;
3929 	axr->axr_cookie = cookie;
3930 	if (RB_INSERT(ax_requests, &(ax->ax_requests), axr) != NULL) {
3931 #ifdef AX_DEBUG
3932 		agentx_log_ax_fatalx(ax, "%s: duplicate packetid", __func__);
3933 #else
3934 		agentx_log_ax_warnx(ax, "%s: duplicate packetid", __func__);
3935 		free(axr);
3936 		agentx_reset(ax);
3937 		return -1;
3938 #endif
3939 	}
3940 
3941 	agentx_wantwrite(ax, ax->ax_fd);
3942 	return 0;
3943 }
3944 
3945 static int
3946 agentx_request_cmp(struct agentx_request *r1,
3947     struct agentx_request *r2)
3948 {
3949 	return r1->axr_packetid < r2->axr_packetid ? -1 :
3950 	    r1->axr_packetid > r2->axr_packetid;
3951 }
3952 
3953 static int
3954 agentx_strcat(char **dst, const char *src)
3955 {
3956 	char *tmp;
3957 	size_t dstlen = 0, buflen = 0, srclen, nbuflen;
3958 
3959 	if (*dst != NULL) {
3960 		dstlen = strlen(*dst);
3961 		buflen = ((dstlen / 512) + 1) * 512;
3962 	}
3963 
3964 	srclen = strlen(src);
3965 	if (*dst == NULL || dstlen + srclen > buflen) {
3966 		nbuflen = (((dstlen + srclen) / 512) + 1) * 512;
3967 		tmp = recallocarray(*dst, buflen, nbuflen, sizeof(*tmp));
3968 		if (tmp == NULL)
3969 			return -1;
3970 		*dst = tmp;
3971 		buflen = nbuflen;
3972 	}
3973 
3974 	(void)strlcat(*dst, src, buflen);
3975 	return 0;
3976 }
3977 
3978 static int
3979 agentx_oidfill(struct ax_oid *oid, const uint32_t oidval[], size_t oidlen,
3980     const char **errstr)
3981 {
3982 	size_t i;
3983 
3984 	if (oidlen < AGENTX_OID_MIN_LEN) {
3985 		*errstr = "oidlen < 2";
3986 		errno = EINVAL;
3987 		return -1;
3988 	}
3989 	if (oidlen > AGENTX_OID_MAX_LEN) {
3990 		*errstr = "oidlen > 128";
3991 		errno = EINVAL;
3992 		return -1;
3993 	}
3994 
3995 	for (i = 0; i < oidlen; i++)
3996 		oid->aoi_id[i] = oidval[i];
3997 	oid->aoi_idlen = oidlen;
3998 	return 0;
3999 }
4000 
4001 void
4002 agentx_read(struct agentx *ax)
4003 {
4004 	struct agentx_session *axs;
4005 	struct agentx_context *axc;
4006 	struct agentx_request axr_search, *axr;
4007 	struct ax_pdu *pdu;
4008 	int error;
4009 
4010 	if ((pdu = ax_recv(ax->ax_ax)) == NULL) {
4011 		if (errno == EAGAIN)
4012 			return;
4013 		agentx_log_ax_warn(ax, "lost connection");
4014 		agentx_reset(ax);
4015 		return;
4016 	}
4017 
4018 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
4019 		if (axs->axs_id == pdu->ap_header.aph_sessionid)
4020 			break;
4021 		if (axs->axs_cstate == AX_CSTATE_WAITOPEN &&
4022 		    axs->axs_packetid == pdu->ap_header.aph_packetid)
4023 			break;
4024 	}
4025 	if (axs == NULL) {
4026 		agentx_log_ax_warnx(ax, "received unexpected session: %d",
4027 		    pdu->ap_header.aph_sessionid);
4028 		ax_pdu_free(pdu);
4029 		agentx_reset(ax);
4030 		return;
4031 	}
4032 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts) {
4033 		if ((pdu->ap_header.aph_flags &
4034 		    AX_PDU_FLAG_NON_DEFAULT_CONTEXT) == 0 &&
4035 		    axc->axc_name_default == 1)
4036 			break;
4037 		if (pdu->ap_header.aph_flags &
4038 		    AX_PDU_FLAG_NON_DEFAULT_CONTEXT &&
4039 		    axc->axc_name_default == 0 &&
4040 		    pdu->ap_context.aos_slen == axc->axc_name.aos_slen &&
4041 		    memcmp(pdu->ap_context.aos_string,
4042 		    axc->axc_name.aos_string, axc->axc_name.aos_slen) == 0)
4043 			break;
4044 	}
4045 	if (pdu->ap_header.aph_type != AX_PDU_TYPE_RESPONSE) {
4046 		if (axc == NULL) {
4047 			agentx_log_ax_warnx(ax, "%s: invalid context",
4048 			    pdu->ap_context.aos_string);
4049 			ax_pdu_free(pdu);
4050 			agentx_reset(ax);
4051 			return;
4052 		}
4053 	}
4054 
4055 	switch (pdu->ap_header.aph_type) {
4056 	case AX_PDU_TYPE_GET:
4057 	case AX_PDU_TYPE_GETNEXT:
4058 	case AX_PDU_TYPE_GETBULK:
4059 		agentx_get_start(axc, pdu);
4060 		break;
4061 	/* Add stubs for set functions */
4062 	case AX_PDU_TYPE_TESTSET:
4063 	case AX_PDU_TYPE_COMMITSET:
4064 	case AX_PDU_TYPE_UNDOSET:
4065 		if (pdu->ap_header.aph_type == AX_PDU_TYPE_TESTSET)
4066 			error = AX_PDU_ERROR_NOTWRITABLE;
4067 		else if (pdu->ap_header.aph_type == AX_PDU_TYPE_COMMITSET)
4068 			error = AX_PDU_ERROR_COMMITFAILED;
4069 		else
4070 			error = AX_PDU_ERROR_UNDOFAILED;
4071 
4072 		agentx_log_axc_debug(axc, "unsupported call: %s",
4073 		    ax_pdutype2string(pdu->ap_header.aph_type));
4074 		if (ax_response(ax->ax_ax, axs->axs_id,
4075 		    pdu->ap_header.aph_transactionid,
4076 		    pdu->ap_header.aph_packetid,
4077 		    0, error, 1, NULL, 0) == -1)
4078 			agentx_log_axc_warn(axc,
4079 			    "transaction: %u packetid: %u: failed to send "
4080 			    "reply", pdu->ap_header.aph_transactionid,
4081 			    pdu->ap_header.aph_packetid);
4082 		if (ax->ax_ax->ax_wblen > 0)
4083 			agentx_wantwrite(ax, ax->ax_fd);
4084 		break;
4085 	case AX_PDU_TYPE_CLEANUPSET:
4086 		agentx_log_ax_debug(ax, "unsupported call: %s",
4087 		    ax_pdutype2string(pdu->ap_header.aph_type));
4088 		break;
4089 	case AX_PDU_TYPE_RESPONSE:
4090 		axr_search.axr_packetid = pdu->ap_header.aph_packetid;
4091 		axr = RB_FIND(ax_requests, &(ax->ax_requests), &axr_search);
4092 		if (axr == NULL) {
4093 			if (axc == NULL)
4094 				agentx_log_ax_warnx(ax, "received "
4095 				    "response on non-request");
4096 			else
4097 				agentx_log_axc_warnx(axc, "received "
4098 				    "response on non-request");
4099 			break;
4100 		}
4101 		if (axc != NULL && pdu->ap_payload.ap_response.ap_error == 0) {
4102 			axc->axc_sysuptime =
4103 			    pdu->ap_payload.ap_response.ap_uptime;
4104 			(void) clock_gettime(CLOCK_MONOTONIC,
4105 			    &(axc->axc_sysuptimespec));
4106 		}
4107 		RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
4108 		(void) axr->axr_cb(pdu, axr->axr_cookie);
4109 		free(axr);
4110 		break;
4111 	default:
4112 		if (axc == NULL)
4113 			agentx_log_ax_warnx(ax, "unsupported call: %s",
4114 			    ax_pdutype2string(pdu->ap_header.aph_type));
4115 		else
4116 			agentx_log_axc_warnx(axc, "unsupported call: %s",
4117 			    ax_pdutype2string(pdu->ap_header.aph_type));
4118 		agentx_reset(ax);
4119 		break;
4120 	}
4121 	ax_pdu_free(pdu);
4122 }
4123 
4124 void
4125 agentx_write(struct agentx *ax)
4126 {
4127 	ssize_t send;
4128 
4129 	if ((send = ax_send(ax->ax_ax)) == -1) {
4130 		if (errno == EAGAIN) {
4131 			agentx_wantwrite(ax, ax->ax_fd);
4132 			return;
4133 		}
4134 		agentx_log_ax_warn(ax, "lost connection");
4135 		agentx_reset(ax);
4136 		return;
4137 	}
4138 	if (send > 0)
4139 		agentx_wantwrite(ax, ax->ax_fd);
4140 }
4141 
4142 RB_GENERATE_STATIC(ax_requests, agentx_request, axr_ax_requests,
4143     agentx_request_cmp)
4144 RB_GENERATE_STATIC(axc_objects, agentx_object, axo_axc_objects,
4145     agentx_object_cmp)
4146