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