xref: /openbsd-src/lib/libagentx/agentx.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*	$OpenBSD: agentx.c,v 1.15 2022/07/19 19:25:42 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 		goto objects_start;
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  objects_start:
1721 	/* TODO Make use of range_subid register */
1722 	for (i = 0; i < axi->axi_objectlen; i++) {
1723 		if (axi->axi_object[i]->axo_dstate == AX_DSTATE_OPEN) {
1724 			if (agentx_object_start(axi->axi_object[i]) == -1)
1725 				return -1;
1726 		}
1727 	}
1728 	return 0;
1729 }
1730 
1731 void
1732 agentx_index_free(struct agentx_index *axi)
1733 {
1734 	size_t i;
1735 	struct agentx_object *axo;
1736 	struct agentx *ax;
1737 	int axfree;
1738 
1739 	if (axi == NULL)
1740 		return;
1741 
1742 	ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
1743 	axfree = ax->ax_free;
1744 	ax->ax_free = 1;
1745 
1746 	if (axi->axi_dstate == AX_DSTATE_CLOSE)
1747 		agentx_log_axc_fatalx(axi->axi_axr->axr_axc,
1748 		    "%s: double free", __func__);
1749 
1750 	/* TODO Do a range_subid unregister before freeing */
1751 	for (i = 0; i < axi->axi_objectlen; i++) {
1752 		axo = axi->axi_object[i];
1753 		if (axo->axo_dstate != AX_DSTATE_CLOSE) {
1754 			agentx_object_free(axo);
1755 			if (axi->axi_object[i] != axo)
1756 				i--;
1757 		}
1758 	}
1759 
1760 	axi->axi_dstate = AX_DSTATE_CLOSE;
1761 
1762 	if (axi->axi_cstate == AX_CSTATE_OPEN)
1763 		(void) agentx_index_close(axi);
1764 	if (!axfree)
1765 		agentx_free_finalize(ax);
1766 }
1767 
1768 static void
1769 agentx_index_free_finalize(struct agentx_index *axi)
1770 {
1771 	struct agentx_region *axr = axi->axi_axr;
1772 
1773 	if (axi->axi_cstate != AX_CSTATE_CLOSE ||
1774 	    axi->axi_dstate != AX_DSTATE_CLOSE ||
1775 	    axi->axi_objectlen != 0)
1776 		return;
1777 
1778 	TAILQ_REMOVE(&(axr->axr_indices), axi, axi_axr_indices);
1779 	ax_varbind_free(&(axi->axi_vb));
1780 	free(axi->axi_object);
1781 	free(axi);
1782 }
1783 
1784 static void
1785 agentx_index_reset(struct agentx_index *axi)
1786 {
1787 	struct agentx *ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
1788 
1789 	axi->axi_cstate = AX_CSTATE_CLOSE;
1790 
1791 	if (!ax->ax_free)
1792 		agentx_free_finalize(ax);
1793 }
1794 
1795 static int
1796 agentx_index_close(struct agentx_index *axi)
1797 {
1798 	struct agentx_region *axr = axi->axi_axr;
1799 	struct agentx_context *axc = axr->axr_axc;
1800 	struct agentx_session *axs = axc->axc_axs;
1801 	struct agentx *ax = axs->axs_ax;
1802 	uint32_t packetid;
1803 
1804 #ifdef AX_DEBUG
1805 	if (axi->axi_cstate != AX_CSTATE_OPEN)
1806 		agentx_log_axc_fatalx(axc,
1807 		    "%s: unexpected index deallocation", __func__);
1808 #endif
1809 
1810 	axi->axi_cstate = AX_CSTATE_WAITCLOSE;
1811 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
1812 		return 0;
1813 
1814 	/* We might be able to bundle, but if we fail we'd have to reorganise */
1815 	packetid = ax_indexdeallocate(ax->ax_ax, axs->axs_id,
1816 	    AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
1817 	if (packetid == 0) {
1818 		agentx_log_axc_warn(axc, "couldn't generate %s",
1819 		    ax_pdutype2string(AX_PDU_TYPE_INDEXDEALLOCATE));
1820 		agentx_reset(ax);
1821 		return -1;
1822 	}
1823 	agentx_log_axc_info(axc, "index %s: deallocating",
1824 	    ax_oid2string(&(axi->axi_vb.avb_oid)));
1825 	return agentx_request(ax, packetid, agentx_index_close_finalize,
1826 	    axi);
1827 }
1828 
1829 static int
1830 agentx_index_close_finalize(struct ax_pdu *pdu, void *cookie)
1831 {
1832 	struct agentx_index *axi = cookie;
1833 	struct agentx_region *axr = axi->axi_axr;
1834 	struct agentx_context *axc = axr->axr_axc;
1835 	struct agentx_session *axs = axc->axc_axs;
1836 	struct agentx *ax = axs->axs_ax;
1837 	struct ax_pdu_response *resp = &(pdu->ap_payload.ap_response);
1838 	int axfree = ax->ax_free;
1839 
1840 #ifdef AX_DEBUG
1841 	if (axi->axi_cstate != AX_CSTATE_WAITCLOSE)
1842 		agentx_log_axc_fatalx(axc, "%s: unexpected indexdeallocate",
1843 		    __func__);
1844 #endif
1845 
1846 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
1847 		agentx_log_axc_warnx(axc,
1848 		    "index %s: couldn't deallocate: %s",
1849 		    ax_oid2string(&(axi->axi_vb.avb_oid)),
1850 		    ax_error2string(resp->ap_error));
1851 		agentx_reset(ax);
1852 		return -1;
1853 	}
1854 
1855 	if (resp->ap_nvarbind != 1) {
1856 		agentx_log_axc_warnx(axc,
1857 		    "index %s: unexpected number of indices",
1858 		    ax_oid2string(&(axr->axr_oid)));
1859 		agentx_reset(ax);
1860 		return -1;
1861 	}
1862 	if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
1863 		agentx_log_axc_warnx(axc, "index %s: unexpected index type",
1864 		    ax_oid2string(&(axr->axr_oid)));
1865 		agentx_reset(ax);
1866 		return -1;
1867 	}
1868 	if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
1869 	    &(axi->axi_vb.avb_oid)) != 0) {
1870 		agentx_log_axc_warnx(axc, "index %s: unexpected oid",
1871 		    ax_oid2string(&(axr->axr_oid)));
1872 		agentx_reset(ax);
1873 		return -1;
1874 	}
1875 	switch (axi->axi_vb.avb_type) {
1876 	case AX_DATA_TYPE_INTEGER:
1877 		if (axi->axi_vb.avb_data.avb_int32 !=
1878 		    resp->ap_varbindlist[0].avb_data.avb_int32) {
1879 			agentx_log_axc_warnx(axc,
1880 			    "index %s: unexpected index value",
1881 			    ax_oid2string(&(axr->axr_oid)));
1882 			agentx_reset(ax);
1883 			return -1;
1884 		}
1885 		break;
1886 	default:
1887 		agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
1888 		    __func__);
1889 	}
1890 
1891 	axi->axi_cstate = AX_CSTATE_CLOSE;
1892 	ax->ax_free = 1;
1893 
1894 	agentx_log_axc_info(axc, "index %s: deallocated",
1895 	    ax_oid2string(&(axi->axi_vb.avb_oid)));
1896 
1897 	if (axr->axr_cstate == AX_CSTATE_OPEN &&
1898 	    axi->axi_dstate == AX_DSTATE_OPEN)
1899 		agentx_index_start(axi);
1900 
1901 	if (!axfree)
1902 		agentx_free_finalize(ax);
1903 	return 0;
1904 }
1905 
1906 struct agentx_object *
1907 agentx_object(struct agentx_region *axr, uint32_t oid[], size_t oidlen,
1908     struct agentx_index *axi[], size_t axilen, int implied,
1909     void (*get)(struct agentx_varbind *))
1910 {
1911 	struct agentx_object *axo, **taxo, axo_search;
1912 	struct agentx_index *laxi;
1913 	const char *errstr;
1914 	int ready = 1;
1915 	size_t i, j;
1916 
1917 	if (axr->axr_dstate == AX_DSTATE_CLOSE)
1918 		agentx_log_axc_fatalx(axr->axr_axc, "%s: use after free",
1919 		    __func__);
1920 	if (axilen > AGENTX_OID_INDEX_MAX_LEN) {
1921 #ifdef AX_DEBUG
1922 		agentx_log_axc_fatalx(axr->axr_axc, "%s: indexlen > %d",
1923 		    __func__, AGENTX_OID_INDEX_MAX_LEN);
1924 #else
1925 		agentx_log_axc_warnx(axr->axr_axc, "%s: indexlen > %d",
1926 		    __func__, AGENTX_OID_INDEX_MAX_LEN);
1927 		errno = EINVAL;
1928 		return NULL;
1929 #endif
1930 	}
1931 
1932 	if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, &errstr) == -1) {
1933 #ifdef AX_DEBUG
1934 		agentx_log_axc_fatalx(axr->axr_axc, "%s: %s", __func__, errstr);
1935 #else
1936 		agentx_log_axc_warnx(axr->axr_axc, "%s: %s", __func__, errstr);
1937 		return NULL;
1938 #endif
1939 	}
1940 
1941 	do {
1942 		if (RB_FIND(axc_objects, &(axr->axr_axc->axc_objects),
1943 		    &axo_search) != NULL) {
1944 #ifdef AX_DEBUG
1945 			agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid "
1946 			    "parent child object relationship", __func__);
1947 #else
1948 			agentx_log_axc_warnx(axr->axr_axc, "%s: invalid "
1949 			    "parent child object relationship", __func__);
1950 			errno = EINVAL;
1951 			return NULL;
1952 #endif
1953 		}
1954 		axo_search.axo_oid.aoi_idlen--;
1955 	} while (axo_search.axo_oid.aoi_idlen > 0);
1956 	axo_search.axo_oid.aoi_idlen = oidlen;
1957 	axo = RB_NFIND(axc_objects, &(axr->axr_axc->axc_objects), &axo_search);
1958 	if (axo != NULL &&
1959 	    ax_oid_cmp(&(axo->axo_oid), &(axo_search.axo_oid)) == 2) {
1960 #ifdef AX_DEBUG
1961 		agentx_log_axc_fatalx(axr->axr_axc, "%s: invalid parent "
1962 		    "child object relationship", __func__);
1963 #else
1964 		agentx_log_axc_warnx(axr->axr_axc, "%s: invalid parent "
1965 		    "child object relationship", __func__);
1966 		errno = EINVAL;
1967 		return NULL;
1968 #endif
1969 	}
1970 	if (implied == 1) {
1971 		laxi = axi[axilen - 1];
1972 		if (laxi->axi_vb.avb_type == AX_DATA_TYPE_OCTETSTRING) {
1973 			if (laxi->axi_vb.avb_data.avb_ostring.aos_slen != 0) {
1974 #ifdef AX_DEBUG
1975 				agentx_log_axc_fatalx(axr->axr_axc,
1976 				    "%s: implied can only be used on strings "
1977 				    "of dynamic length", __func__);
1978 #else
1979 				agentx_log_axc_warnx(axr->axr_axc,
1980 				    "%s: implied can only be used on strings "
1981 				    "of dynamic length", __func__);
1982 				errno = EINVAL;
1983 				return NULL;
1984 #endif
1985 			}
1986 		} else if (laxi->axi_vb.avb_type == AX_DATA_TYPE_OID) {
1987 			if (laxi->axi_vb.avb_data.avb_oid.aoi_idlen != 0) {
1988 #ifdef AX_DEBUG
1989 				agentx_log_axc_fatalx(axr->axr_axc,
1990 				    "%s: implied can only be used on oids of "
1991 				    "dynamic length", __func__);
1992 #else
1993 				agentx_log_axc_warnx(axr->axr_axc,
1994 				    "%s: implied can only be used on oids of "
1995 				    "dynamic length", __func__);
1996 				errno = EINVAL;
1997 				return NULL;
1998 #endif
1999 			}
2000 		} else {
2001 #ifdef AX_DEBUG
2002 			agentx_log_axc_fatalx(axr->axr_axc, "%s: implied "
2003 			    "can only be set on oid and string indices",
2004 			    __func__);
2005 #else
2006 			agentx_log_axc_warnx(axr->axr_axc, "%s: implied can "
2007 			    "only be set on oid and string indices", __func__);
2008 			errno = EINVAL;
2009 			return NULL;
2010 #endif
2011 		}
2012 	}
2013 
2014 	ready = axr->axr_cstate == AX_CSTATE_OPEN;
2015 	if ((axo = calloc(1, sizeof(*axo))) == NULL)
2016 		return NULL;
2017 	axo->axo_axr = axr;
2018 	bcopy(&(axo_search.axo_oid), &(axo->axo_oid), sizeof(axo->axo_oid));
2019 	for (i = 0; i < axilen; i++) {
2020 		axo->axo_index[i] = axi[i];
2021 		if (axi[i]->axi_objectlen == axi[i]->axi_objectsize) {
2022 			taxo = recallocarray(axi[i]->axi_object,
2023 			    axi[i]->axi_objectlen, axi[i]->axi_objectlen + 1,
2024 			    sizeof(*axi[i]->axi_object));
2025 			if (taxo == NULL) {
2026 				free(axo);
2027 				return NULL;
2028 			}
2029 			axi[i]->axi_object = taxo;
2030 			axi[i]->axi_objectsize = axi[i]->axi_objectlen + 1;
2031 		}
2032 		for (j = 0; j < axi[i]->axi_objectlen; j++) {
2033 			if (ax_oid_cmp(&(axo->axo_oid),
2034 			    &(axi[i]->axi_object[j]->axo_oid)) < 0) {
2035 				memmove(&(axi[i]->axi_object[j + 1]),
2036 				    &(axi[i]->axi_object[j]),
2037 				    sizeof(*(axi[i]->axi_object)) *
2038 				    (axi[i]->axi_objectlen - j));
2039 				break;
2040 			}
2041 		}
2042 		axi[i]->axi_object[j] = axo;
2043 		axi[i]->axi_objectlen++;
2044 		if (axi[i]->axi_cstate != AX_CSTATE_OPEN)
2045 			ready = 0;
2046 	}
2047 	axo->axo_indexlen = axilen;
2048 	axo->axo_implied = implied;
2049 	axo->axo_timeout = 0;
2050 	axo->axo_lock = 0;
2051 	axo->axo_get = get;
2052 	axo->axo_cstate = AX_CSTATE_CLOSE;
2053 	axo->axo_dstate = AX_DSTATE_OPEN;
2054 
2055 	TAILQ_INSERT_TAIL(&(axr->axr_objects), axo, axo_axr_objects);
2056 	RB_INSERT(axc_objects, &(axr->axr_axc->axc_objects), axo);
2057 
2058 	if (ready)
2059 		agentx_object_start(axo);
2060 
2061 	return axo;
2062 }
2063 
2064 static int
2065 agentx_object_start(struct agentx_object *axo)
2066 {
2067 	struct agentx_region *axr = axo->axo_axr;
2068 	struct agentx_context *axc = axr->axr_axc;
2069 	struct agentx_session *axs = axc->axc_axs;
2070 	struct agentx *ax = axs->axs_ax;
2071 	struct ax_oid oid;
2072 	char oids[1024];
2073 	size_t i;
2074 	int needregister = 0;
2075 	uint32_t packetid;
2076 	uint8_t flags = AX_PDU_FLAG_INSTANCE_REGISTRATION;
2077 
2078 #ifdef AX_DEBUG
2079 	if (axr->axr_cstate != AX_CSTATE_OPEN ||
2080 	    axo->axo_cstate != AX_CSTATE_CLOSE ||
2081 	    axo->axo_dstate != AX_DSTATE_OPEN)
2082 		agentx_log_axc_fatalx(axc,
2083 		    "%s: unexpected object registration", __func__);
2084 #endif
2085 
2086 	if (axo->axo_timeout != 0)
2087 		needregister = 1;
2088 	for (i = 0; i < axo->axo_indexlen; i++) {
2089 		if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
2090 			return 0;
2091 		if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
2092 			needregister = 1;
2093 	}
2094 	if (!needregister) {
2095 		axo->axo_cstate = AX_CSTATE_WAITOPEN;
2096 		agentx_object_finalize(NULL, axo);
2097 		return 0;
2098 	}
2099 
2100 	bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
2101 	for (i = 0; i < axo->axo_indexlen; i++) {
2102 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2103 			flags = 0;
2104 			break;
2105 		}
2106 #ifdef AX_DEBUG
2107 		if (axo->axo_index[i]->axi_vb.avb_type !=
2108 		    AX_DATA_TYPE_INTEGER)
2109 			agentx_log_axc_fatalx(axc,
2110 			    "%s: Unsupported allocated index type", __func__);
2111 #endif
2112 		oid.aoi_id[oid.aoi_idlen++] =
2113 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2114 	}
2115 	packetid = ax_register(ax->ax_ax, flags, axs->axs_id,
2116 	    AGENTX_CONTEXT_CTX(axc), axo->axo_timeout,
2117 	    AX_PRIORITY_DEFAULT, 0, &oid, 0);
2118 	if (packetid == 0) {
2119 		agentx_log_axc_warn(axc, "couldn't generate %s",
2120 		    ax_pdutype2string(AX_PDU_TYPE_REGISTER));
2121 		agentx_reset(ax);
2122 		return -1;
2123 	}
2124 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2125 	agentx_log_axc_info(axc, "object %s (%s %s): opening",
2126 	    oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
2127 	axo->axo_cstate = AX_CSTATE_WAITOPEN;
2128 	return agentx_request(ax, packetid, agentx_object_finalize, axo);
2129 }
2130 
2131 static int
2132 agentx_object_finalize(struct ax_pdu *pdu, void *cookie)
2133 {
2134 	struct agentx_object *axo = cookie;
2135 	struct agentx_context *axc = axo->axo_axr->axr_axc;
2136 	struct ax_oid oid;
2137 	char oids[1024];
2138 	size_t i;
2139 	uint8_t flags = 1;
2140 
2141 #ifdef AX_DEBUG
2142 	if (axo->axo_cstate != AX_CSTATE_WAITOPEN)
2143 		agentx_log_axc_fatalx(axc, "%s: not expecting object open",
2144 		    __func__);
2145 #endif
2146 
2147 	if (pdu == NULL) {
2148 		axo->axo_cstate = AX_CSTATE_OPEN;
2149 		return 0;
2150 	}
2151 
2152 	bcopy(&(axo->axo_oid), &oid, sizeof(oid));
2153 	for (i = 0; i < axo->axo_indexlen; i++) {
2154 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2155 			flags = 0;
2156 			break;
2157 		}
2158 #ifdef AX_DEBUG
2159 		if (axo->axo_index[i]->axi_vb.avb_type !=
2160 		    AX_DATA_TYPE_INTEGER)
2161 			agentx_log_axc_fatalx(axc,
2162 			    "%s: Unsupported allocated index type", __func__);
2163 #endif
2164 
2165 		oid.aoi_id[oid.aoi_idlen++] =
2166 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2167 	}
2168 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2169 
2170 	/*
2171 	 * We should only be here for table objects with registered indices.
2172 	 * If we fail here something is misconfigured and the admin should fix
2173 	 * it.
2174 	 */
2175 	if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
2176 		axo->axo_cstate = AX_CSTATE_CLOSE;
2177 		agentx_log_axc_info(axc, "object %s (%s %s): %s",
2178 		    oids, flags ? "instance" : "region", ax_oid2string(&oid),
2179 		    ax_error2string(pdu->ap_payload.ap_response.ap_error));
2180 		return 0;
2181 	}
2182 	axo->axo_cstate = AX_CSTATE_OPEN;
2183 	agentx_log_axc_info(axc, "object %s (%s %s): open", oids,
2184 	    flags ? "instance" : "region", ax_oid2string(&oid));
2185 
2186 	if (axo->axo_dstate == AX_DSTATE_CLOSE)
2187 		return agentx_object_close(axo);
2188 
2189 	return 0;
2190 }
2191 
2192 static int
2193 agentx_object_lock(struct agentx_object *axo)
2194 {
2195 	if (axo->axo_lock == UINT32_MAX) {
2196 		agentx_log_axc_warnx(axo->axo_axr->axr_axc,
2197 		    "%s: axo_lock == %u", __func__, UINT32_MAX);
2198 		return -1;
2199 	}
2200 	axo->axo_lock++;
2201 	return 0;
2202 }
2203 
2204 static void
2205 agentx_object_unlock(struct agentx_object *axo)
2206 {
2207 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2208 
2209 #ifdef AX_DEBUG
2210 	if (axo->axo_lock == 0)
2211 		agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
2212 		    "%s: axo_lock == 0", __func__);
2213 #endif
2214 	axo->axo_lock--;
2215 	if (axo->axo_lock == 0) {
2216 		if (!ax->ax_free)
2217 			agentx_free_finalize(ax);
2218 	}
2219 }
2220 
2221 static int
2222 agentx_object_close(struct agentx_object *axo)
2223 {
2224 	struct agentx_context *axc = axo->axo_axr->axr_axc;
2225 	struct agentx_session *axs = axc->axc_axs;
2226 	struct agentx *ax = axs->axs_ax;
2227 	struct ax_oid oid;
2228 	char oids[1024];
2229 	size_t i;
2230 	int needclose = 0;
2231 	uint32_t packetid;
2232 	uint8_t flags = 1;
2233 
2234 #ifdef AX_DEBUG
2235 	if (axo->axo_cstate != AX_CSTATE_OPEN)
2236 		agentx_log_axc_fatalx(axc, "%s: unexpected object close",
2237 		    __func__);
2238 #endif
2239 
2240 	for (i = 0; i < axo->axo_indexlen; i++) {
2241 #ifdef AX_DEBUG
2242 		if (axo->axo_index[i]->axi_cstate != AX_CSTATE_OPEN)
2243 			agentx_log_axc_fatalx(axc,
2244 			    "%s: Object open while index closed", __func__);
2245 #endif
2246 		if (axo->axo_index[i]->axi_type != AXI_TYPE_DYNAMIC)
2247 			needclose = 1;
2248 	}
2249 	axo->axo_cstate = AX_CSTATE_WAITCLOSE;
2250 	if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
2251 		return 0;
2252 	if (!needclose) {
2253 		agentx_object_close_finalize(NULL, axo);
2254 		return 0;
2255 	}
2256 
2257 	bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
2258 	for (i = 0; i < axo->axo_indexlen; i++) {
2259 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2260 			flags = 0;
2261 			break;
2262 		}
2263 #ifdef AX_DEBUG
2264 		if (axo->axo_index[i]->axi_vb.avb_type !=
2265 		    AX_DATA_TYPE_INTEGER)
2266 			agentx_log_axc_fatalx(axc,
2267 			    "%s: Unsupported allocated index type", __func__);
2268 #endif
2269 		oid.aoi_id[oid.aoi_idlen++] =
2270 		    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2271 	}
2272 	packetid = ax_unregister(ax->ax_ax, axs->axs_id,
2273 	    AGENTX_CONTEXT_CTX(axc), AX_PRIORITY_DEFAULT, 0, &oid, 0);
2274 	if (packetid == 0) {
2275 		agentx_log_axc_warn(axc, "couldn't generate %s",
2276 		    ax_pdutype2string(AX_PDU_TYPE_UNREGISTER));
2277 		agentx_reset(ax);
2278 		return -1;
2279 	}
2280 	strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2281 	agentx_log_axc_info(axc, "object %s (%s %s): closing",
2282 	    oids, flags ? "instance" : "region", ax_oid2string(&(oid)));
2283 	return agentx_request(ax, packetid, agentx_object_close_finalize,
2284 	    axo);
2285 }
2286 
2287 static int
2288 agentx_object_close_finalize(struct ax_pdu *pdu, void *cookie)
2289 {
2290 	struct agentx_object *axo = cookie;
2291 	struct agentx_region *axr = axo->axo_axr;
2292 	struct agentx_context *axc = axr->axr_axc;
2293 	struct agentx_session *axs = axc->axc_axs;
2294 	struct agentx *ax = axs->axs_ax;
2295 	struct ax_oid oid;
2296 	char oids[1024];
2297 	uint8_t flags = 1;
2298 	size_t i;
2299 	int axfree = ax->ax_free;
2300 
2301 #ifdef AX_DEBUG
2302 	if (axo->axo_cstate != AX_CSTATE_WAITCLOSE)
2303 		agentx_log_axc_fatalx(axc,
2304 		    "%s: unexpected object unregister", __func__);
2305 #endif
2306 
2307 	if (pdu != NULL) {
2308 		bcopy(&(axo->axo_oid), &(oid), sizeof(oid));
2309 		for (i = 0; i < axo->axo_indexlen; i++) {
2310 			if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC) {
2311 				flags = 0;
2312 				break;
2313 			}
2314 #ifdef AX_DEBUG
2315 			if (axo->axo_index[i]->axi_vb.avb_type !=
2316 			    AX_DATA_TYPE_INTEGER)
2317 				agentx_log_axc_fatalx(axc,
2318 				    "%s: Unsupported allocated index type",
2319 				    __func__);
2320 #endif
2321 			oid.aoi_id[oid.aoi_idlen++] =
2322 			    axo->axo_index[i]->axi_vb.avb_data.avb_int32;
2323 		}
2324 		strlcpy(oids, ax_oid2string(&(axo->axo_oid)), sizeof(oids));
2325 		if (pdu->ap_payload.ap_response.ap_error !=
2326 		    AX_PDU_ERROR_NOERROR) {
2327 			agentx_log_axc_warnx(axc,
2328 			    "closing object %s (%s %s): %s", oids,
2329 			    flags ? "instance" : "region",
2330 			    ax_oid2string(&oid), ax_error2string(
2331 			    pdu->ap_payload.ap_response.ap_error));
2332 			agentx_reset(ax);
2333 			return -1;
2334 		}
2335 		agentx_log_axc_info(axc, "object %s (%s %s): closed", oids,
2336 		    flags ? "instance" : "region", ax_oid2string(&oid));
2337 	}
2338 
2339 	ax->ax_free = 1;
2340 	if (axr->axr_cstate == AX_CSTATE_OPEN &&
2341 	    axo->axo_dstate == AX_DSTATE_OPEN)
2342 		agentx_object_start(axo);
2343 
2344 	if (!axfree)
2345 		agentx_free_finalize(ax);
2346 
2347 	return 0;
2348 }
2349 
2350 void
2351 agentx_object_free(struct agentx_object *axo)
2352 {
2353 	struct agentx *ax;
2354 	int axfree;
2355 
2356 	if (axo == NULL)
2357 		return;
2358 
2359 	ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2360 	axfree = ax->ax_free;
2361 	ax->ax_free = 1;
2362 
2363 	if (axo->axo_dstate == AX_DSTATE_CLOSE)
2364 		agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
2365 		    "%s: double free", __func__);
2366 
2367 	axo->axo_dstate = AX_DSTATE_CLOSE;
2368 
2369 	if (axo->axo_cstate == AX_CSTATE_OPEN)
2370 		agentx_object_close(axo);
2371 	if (!axfree)
2372 		agentx_free_finalize(ax);
2373 }
2374 
2375 static void
2376 agentx_object_free_finalize(struct agentx_object *axo)
2377 {
2378 #ifdef AX_DEBUG
2379 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2380 #endif
2381 	size_t i, j;
2382 	int found;
2383 
2384 	if (axo->axo_dstate != AX_DSTATE_CLOSE ||
2385 	    axo->axo_cstate != AX_CSTATE_CLOSE ||
2386 	    axo->axo_lock != 0)
2387 		return;
2388 
2389 	RB_REMOVE(axc_objects, &(axo->axo_axr->axr_axc->axc_objects), axo);
2390 	TAILQ_REMOVE(&(axo->axo_axr->axr_objects), axo, axo_axr_objects);
2391 
2392 	for (i = 0; i < axo->axo_indexlen; i++) {
2393 		found = 0;
2394 		for (j = 0; j < axo->axo_index[i]->axi_objectlen; j++) {
2395 			if (axo->axo_index[i]->axi_object[j] == axo)
2396 				found = 1;
2397 			if (found && j + 1 != axo->axo_index[i]->axi_objectlen)
2398 				axo->axo_index[i]->axi_object[j] =
2399 				    axo->axo_index[i]->axi_object[j + 1];
2400 		}
2401 #ifdef AX_DEBUG
2402 		if (!found)
2403 			agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
2404 			    "%s: object not found in index", __func__);
2405 #endif
2406 		axo->axo_index[i]->axi_objectlen--;
2407 	}
2408 
2409 	free(axo);
2410 }
2411 
2412 static void
2413 agentx_object_reset(struct agentx_object *axo)
2414 {
2415 	struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
2416 
2417 	axo->axo_cstate = AX_CSTATE_CLOSE;
2418 
2419 	if (!ax->ax_free)
2420 		agentx_free_finalize(ax);
2421 }
2422 
2423 static int
2424 agentx_object_cmp(struct agentx_object *o1, struct agentx_object *o2)
2425 {
2426 	return ax_oid_cmp(&(o1->axo_oid), &(o2->axo_oid));
2427 }
2428 
2429 static int
2430 agentx_object_implied(struct agentx_object *axo,
2431     struct agentx_index *axi)
2432 {
2433 	size_t i = 0;
2434 
2435 	for (i = 0; i < axo->axo_indexlen; i++) {
2436 		if (axo->axo_index[i] == axi) {
2437 			if (axi->axi_vb.avb_data.avb_ostring.aos_slen != 0)
2438 				return 1;
2439 			else if (i == axo->axo_indexlen - 1)
2440 				return axo->axo_implied;
2441 			return 0;
2442 		}
2443 	}
2444 #ifdef AX_DEBUG
2445 	agentx_log_axc_fatalx(axo->axo_axr->axr_axc, "%s: unsupported index",
2446 	    __func__);
2447 #endif
2448 	return 0;
2449 }
2450 
2451 static void
2452 agentx_get_start(struct agentx_context *axc, struct ax_pdu *pdu)
2453 {
2454 	struct agentx_session *axs = axc->axc_axs;
2455 	struct agentx *ax = axs->axs_ax;
2456 	struct agentx_get *axg, taxg;
2457 	struct ax_pdu_searchrangelist *srl;
2458 	char *logmsg = NULL;
2459 	size_t i, j;
2460 	int fail = 0;
2461 
2462 	if ((axg = calloc(1, sizeof(*axg))) == NULL) {
2463 		taxg.axg_sessionid = pdu->ap_header.aph_sessionid;
2464 		taxg.axg_transactionid = pdu->ap_header.aph_transactionid;
2465 		taxg.axg_packetid = pdu->ap_header.aph_packetid;
2466 		taxg.axg_context_default = axc->axc_name_default;
2467 		taxg.axg_fd = axc->axc_axs->axs_ax->ax_fd;
2468 		agentx_log_axg_warn(&taxg, "Couldn't parse request");
2469 		agentx_reset(ax);
2470 		return;
2471 	}
2472 
2473 	axg->axg_sessionid = pdu->ap_header.aph_sessionid;
2474 	axg->axg_transactionid = pdu->ap_header.aph_transactionid;
2475 	axg->axg_packetid = pdu->ap_header.aph_packetid;
2476 	axg->axg_context_default = axc->axc_name_default;
2477 	axg->axg_fd = axc->axc_axs->axs_ax->ax_fd;
2478 	if (!axc->axc_name_default) {
2479 		axg->axg_context.aos_string =
2480 		    (unsigned char *)strdup((char *)axc->axc_name.aos_string);
2481 		if (axg->axg_context.aos_string == NULL) {
2482 			agentx_log_axg_warn(axg, "Couldn't parse request");
2483 			free(axg);
2484 			agentx_reset(ax);
2485 			return;
2486 		}
2487 	}
2488 	axg->axg_context.aos_slen = axc->axc_name.aos_slen;
2489 	axg->axg_type = pdu->ap_header.aph_type;
2490 	axg->axg_axc = axc;
2491 	TAILQ_INSERT_TAIL(&(ax->ax_getreqs), axg, axg_ax_getreqs);
2492 	if (axg->axg_type == AX_PDU_TYPE_GET ||
2493 	    axg->axg_type == AX_PDU_TYPE_GETNEXT) {
2494 		srl = &(pdu->ap_payload.ap_srl);
2495 		axg->axg_nvarbind = srl->ap_nsr;
2496 	} else {
2497 		axg->axg_nonrep = pdu->ap_payload.ap_getbulk.ap_nonrep;
2498 		axg->axg_maxrep = pdu->ap_payload.ap_getbulk.ap_maxrep;
2499 		srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
2500 		axg->axg_nvarbind = ((srl->ap_nsr - axg->axg_nonrep) *
2501 		    axg->axg_maxrep) + axg->axg_nonrep;
2502 	}
2503 
2504 	if ((axg->axg_varbind = calloc(axg->axg_nvarbind,
2505 	    sizeof(*(axg->axg_varbind)))) == NULL) {
2506 		agentx_log_axg_warn(axg, "Couldn't parse request");
2507 		agentx_get_free(axg);
2508 		agentx_reset(ax);
2509 		return;
2510 	}
2511 
2512 	/* XXX net-snmp doesn't use getbulk, so untested */
2513 	/* Two loops: varbind after needs to be initialized */
2514 	for (i = 0; i < srl->ap_nsr; i++) {
2515 		if (i < axg->axg_nonrep ||
2516 		    axg->axg_type != AX_PDU_TYPE_GETBULK)
2517 			j = i;
2518 		else if (axg->axg_maxrep == 0)
2519 			break;
2520 		else
2521 			j = (axg->axg_maxrep * i) + axg->axg_nonrep;
2522 		bcopy(&(srl->ap_sr[i].asr_start),
2523 		    &(axg->axg_varbind[j].axv_vb.avb_oid),
2524 		    sizeof(srl->ap_sr[i].asr_start));
2525 		bcopy(&(srl->ap_sr[i].asr_start),
2526 		    &(axg->axg_varbind[j].axv_start),
2527 		    sizeof(srl->ap_sr[i].asr_start));
2528 		bcopy(&(srl->ap_sr[i].asr_stop),
2529 		    &(axg->axg_varbind[j].axv_end),
2530 		    sizeof(srl->ap_sr[i].asr_stop));
2531 		axg->axg_varbind[j].axv_initialized = 1;
2532 		axg->axg_varbind[j].axv_axg = axg;
2533 		axg->axg_varbind[j].axv_include =
2534 		    srl->ap_sr[i].asr_start.aoi_include;
2535 		if (j == 0)
2536 			fail |= agentx_strcat(&logmsg, " {");
2537 		else
2538 			fail |= agentx_strcat(&logmsg, ",{");
2539 		fail |= agentx_strcat(&logmsg,
2540 		    ax_oid2string(&(srl->ap_sr[i].asr_start)));
2541 		if (srl->ap_sr[i].asr_start.aoi_include)
2542 			fail |= agentx_strcat(&logmsg, " (inclusive)");
2543 		if (srl->ap_sr[i].asr_stop.aoi_idlen != 0) {
2544 			fail |= agentx_strcat(&logmsg, " - ");
2545 			fail |= agentx_strcat(&logmsg,
2546 			    ax_oid2string(&(srl->ap_sr[i].asr_stop)));
2547 		}
2548 		fail |= agentx_strcat(&logmsg, "}");
2549 		if (fail) {
2550 			agentx_log_axg_warn(axg, "Couldn't parse request");
2551 			free(logmsg);
2552 			agentx_get_free(axg);
2553 			agentx_reset(ax);
2554 			return;
2555 		}
2556 	}
2557 
2558 	agentx_log_axg_debug(axg, "%s:%s",
2559 	    ax_pdutype2string(axg->axg_type), logmsg);
2560 	free(logmsg);
2561 
2562 	for (i = 0; i < srl->ap_nsr; i++) {
2563 		if (i < axg->axg_nonrep ||
2564 		    axg->axg_type != AX_PDU_TYPE_GETBULK)
2565 			j = i;
2566 		else if (axg->axg_maxrep == 0)
2567 			break;
2568 		else
2569 			j = (axg->axg_maxrep * i) + axg->axg_nonrep;
2570 		agentx_varbind_start(&(axg->axg_varbind[j]));
2571 	}
2572 }
2573 
2574 static void
2575 agentx_get_finalize(struct agentx_get *axg)
2576 {
2577 	struct agentx_context *axc = axg->axg_axc;
2578 	struct agentx_session *axs = axc->axc_axs;
2579 	struct agentx *ax = axs->axs_ax;
2580 	size_t i, j, nvarbind = 0;
2581 	uint16_t error = 0, index = 0;
2582 	struct ax_varbind *vbl;
2583 	char *logmsg = NULL;
2584 	int fail = 0;
2585 
2586 	for (i = 0; i < axg->axg_nvarbind; i++) {
2587 		if (axg->axg_varbind[i].axv_initialized) {
2588 			if (axg->axg_varbind[i].axv_vb.avb_type == 0)
2589 				return;
2590 			nvarbind++;
2591 		}
2592 	}
2593 
2594 	if (axg->axg_axc == NULL) {
2595 		agentx_get_free(axg);
2596 		return;
2597 	}
2598 
2599 	if ((vbl = calloc(nvarbind, sizeof(*vbl))) == NULL) {
2600 		agentx_log_axg_warn(axg, "Couldn't parse request");
2601 		agentx_get_free(axg);
2602 		agentx_reset(ax);
2603 		return;
2604 	}
2605 	for (i = 0, j = 0; i < axg->axg_nvarbind; i++) {
2606 		if (axg->axg_varbind[i].axv_initialized) {
2607 			memcpy(&(vbl[j]), &(axg->axg_varbind[i].axv_vb),
2608 			    sizeof(*vbl));
2609 			if (error == 0 && axg->axg_varbind[i].axv_error !=
2610 			    AX_PDU_ERROR_NOERROR) {
2611 				error = axg->axg_varbind[i].axv_error;
2612 				index = j + 1;
2613 			}
2614 			if (j == 0)
2615 				fail |= agentx_strcat(&logmsg, " {");
2616 			else
2617 				fail |= agentx_strcat(&logmsg, ",{");
2618 			fail |= agentx_strcat(&logmsg,
2619 			    ax_varbind2string(&(vbl[j])));
2620 			if (axg->axg_varbind[i].axv_error !=
2621 			    AX_PDU_ERROR_NOERROR) {
2622 				fail |= agentx_strcat(&logmsg, "(");
2623 				fail |= agentx_strcat(&logmsg,
2624 				    ax_error2string(
2625 				    axg->axg_varbind[i].axv_error));
2626 				fail |= agentx_strcat(&logmsg, ")");
2627 			}
2628 			fail |= agentx_strcat(&logmsg, "}");
2629 			if (fail) {
2630 				agentx_log_axg_warn(axg,
2631 				    "Couldn't parse request");
2632 				free(logmsg);
2633 				agentx_get_free(axg);
2634 				return;
2635 			}
2636 			j++;
2637 		}
2638 	}
2639 	agentx_log_axg_debug(axg, "response:%s", logmsg);
2640 	free(logmsg);
2641 
2642 	if (ax_response(ax->ax_ax, axs->axs_id, axg->axg_transactionid,
2643 	    axg->axg_packetid, AGENTX_CONTEXT_CTX(axc), 0, error, index,
2644 	    vbl, nvarbind) == -1) {
2645 		agentx_log_axg_warn(axg, "Couldn't parse request");
2646 		agentx_reset(ax);
2647 	} else
2648 		agentx_wantwrite(ax, ax->ax_fd);
2649 	free(vbl);
2650 	agentx_get_free(axg);
2651 }
2652 
2653 void
2654 agentx_get_free(struct agentx_get *axg)
2655 {
2656 	struct agentx_varbind *axv;
2657 	struct agentx_object *axo;
2658 	struct agentx *ax = axg->axg_axc->axc_axs->axs_ax;
2659 	struct agentx_varbind_index *index;
2660 	size_t i, j;
2661 
2662 	if (axg->axg_axc != NULL)
2663 		TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
2664 
2665 	for (i = 0; i < axg->axg_nvarbind; i++) {
2666 		axv = &(axg->axg_varbind[i]);
2667 		for (j = 0; axv->axv_axo != NULL &&
2668 		    j < axv->axv_axo->axo_indexlen; j++) {
2669 			axo = axv->axv_axo;
2670 			index = &(axv->axv_index[j]);
2671 			if (axo->axo_index[j]->axi_vb.avb_type ==
2672 			    AX_DATA_TYPE_OCTETSTRING ||
2673 			    axo->axo_index[j]->axi_vb.avb_type ==
2674 			    AX_DATA_TYPE_IPADDRESS)
2675 				free(index->axv_idata.avb_ostring.aos_string);
2676 		}
2677 		ax_varbind_free(&(axg->axg_varbind[i].axv_vb));
2678 	}
2679 
2680 	free(axg->axg_context.aos_string);
2681 	free(axg->axg_varbind);
2682 	free(axg);
2683 }
2684 
2685 static void
2686 agentx_varbind_start(struct agentx_varbind *axv)
2687 {
2688 	struct agentx_get *axg = axv->axv_axg;
2689 	struct agentx_context *axc = axg->axg_axc;
2690 	struct agentx_object *axo, axo_search;
2691 	struct agentx_varbind_index *index;
2692 	struct ax_oid *oid;
2693 	union ax_data *data;
2694 	struct in_addr *ipaddress;
2695 	unsigned char *ipbytes;
2696 	size_t i, j, k;
2697 	int overflow = 0, dynamic;
2698 
2699 #ifdef AX_DEBUG
2700 	if (!axv->axv_initialized)
2701 		agentx_log_axg_fatalx(axv->axv_axg,
2702 		    "%s: axv_initialized not set", __func__);
2703 #endif
2704 
2705 	bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
2706 	    sizeof(axo_search.axo_oid));
2707 
2708 	do {
2709 		axo = RB_FIND(axc_objects, &(axc->axc_objects), &axo_search);
2710 		if (axo_search.axo_oid.aoi_idlen > 0)
2711 			axo_search.axo_oid.aoi_idlen--;
2712 	} while (axo == NULL && axo_search.axo_oid.aoi_idlen > 0);
2713 	if (axo == NULL || axo->axo_cstate != AX_CSTATE_OPEN) {
2714 		axv->axv_include = 1;
2715 		if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
2716 			agentx_varbind_nosuchobject(axv);
2717 			return;
2718 		}
2719 		bcopy(&(axv->axv_vb.avb_oid), &(axo_search.axo_oid),
2720 		    sizeof(axo_search.axo_oid));
2721 		axo = RB_NFIND(axc_objects, &(axc->axc_objects), &axo_search);
2722 getnext:
2723 		while (axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
2724 			axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
2725 		if (axo == NULL) {
2726 			agentx_varbind_endofmibview(axv);
2727 			return;
2728 		}
2729 		bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
2730 		    sizeof(axo->axo_oid));
2731 	}
2732 	axv->axv_axo = axo;
2733 	axv->axv_indexlen = axo->axo_indexlen;
2734 	if (agentx_object_lock(axo) == -1) {
2735 		agentx_varbind_error_type(axv,
2736 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
2737 		return;
2738 	}
2739 
2740 	oid = &(axv->axv_vb.avb_oid);
2741 	if (axo->axo_indexlen == 0) {
2742 		if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
2743 			if (oid->aoi_idlen != axo->axo_oid.aoi_idlen + 1 ||
2744 			    oid->aoi_id[oid->aoi_idlen - 1] != 0) {
2745 				agentx_varbind_nosuchinstance(axv);
2746 				return;
2747 			}
2748 		} else {
2749 			if (oid->aoi_idlen == axo->axo_oid.aoi_idlen) {
2750 				oid->aoi_id[oid->aoi_idlen++] = 0;
2751 				axv->axv_include = 1;
2752 			} else {
2753 				axv->axv_axo = NULL;
2754 				agentx_object_unlock(axo);
2755 				axo = RB_NEXT(axc_objects, &(axc->axc_objects),
2756 				    axo);
2757 				goto getnext;
2758 			}
2759 		}
2760 		j = oid->aoi_idlen;
2761 	} else
2762 		j = axo->axo_oid.aoi_idlen;
2763 /*
2764  * We can't trust what the client gives us, so sometimes we need to map it to
2765  * index type.
2766  * - AX_PDU_TYPE_GET: we always return AX_DATA_TYPE_NOSUCHINSTANCE
2767  * - AX_PDU_TYPE_GETNEXT:
2768  *   - Missing OID digits to match indices or !dynamic indices
2769  *     (AX_DATA_TYPE_INTEGER) undeflows will result in the following indices to
2770  *     be NUL-initialized and the request type will be set to
2771  *     AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE
2772  *   - An overflow can happen on AX_DATA_TYPE_OCTETSTRING and
2773  *     AX_DATA_TYPE_IPADDRESS data, and AX_DATA_TYPE_OCTETSTRING and
2774  *     AX_DATA_TYPE_OID length. This results in request type being set to
2775  *     AGENTX_REQUEST_TYPE_GETNEXT and will set the index to its maximum
2776  *     value:
2777  *     - AX_DATA_TYPE_INTEGER: UINT32_MAX
2778  *     - AX_DATA_TYPE_OCTETSTRING: aos_slen = UINT32_MAX and
2779  *       aos_string = NULL
2780  *     - AX_DATA_TYPE_OID: aoi_idlen = UINT32_MAX and aoi_id[x] = UINT32_MAX
2781  *     - AX_DATA_TYPE_IPADDRESS: 255.255.255.255
2782  */
2783 	for (dynamic = 0, i = 0; i < axo->axo_indexlen; i++, j++) {
2784 		index = &(axv->axv_index[i]);
2785 		index->axv_axi = axo->axo_index[i];
2786 		data = &(index->axv_idata);
2787 		if (axo->axo_index[i]->axi_type == AXI_TYPE_DYNAMIC)
2788 			dynamic = 1;
2789 		switch (axo->axo_index[i]->axi_vb.avb_type) {
2790 		case AX_DATA_TYPE_INTEGER:
2791 			if (index->axv_axi->axi_type != AXI_TYPE_DYNAMIC) {
2792 				index->axv_idata.avb_int32 =
2793 				    index->axv_axi->axi_vb.avb_data.avb_int32;
2794 				if (overflow == 0) {
2795 					if ((uint32_t)index->axv_idata.avb_int32 >
2796 					    oid->aoi_id[j])
2797 						overflow = -1;
2798 					else if ((uint32_t)index->axv_idata.avb_int32 <
2799 					    oid->aoi_id[j])
2800 						overflow = 1;
2801 				}
2802 			} else if (overflow == 1)
2803 				index->axv_idata.avb_int32 = INT32_MAX;
2804 			else if (j >= oid->aoi_idlen || overflow == -1)
2805 				index->axv_idata.avb_int32 = 0;
2806 			else {
2807 				if (oid->aoi_id[j] > INT32_MAX) {
2808 					index->axv_idata.avb_int32 = INT32_MAX;
2809 					overflow = 1;
2810 				} else
2811 					index->axv_idata.avb_int32 =
2812 					    oid->aoi_id[j];
2813 			}
2814 			break;
2815 		case AX_DATA_TYPE_OCTETSTRING:
2816 			if (overflow == 1) {
2817 				data->avb_ostring.aos_slen = UINT32_MAX;
2818 				data->avb_ostring.aos_string = NULL;
2819 				continue;
2820 			} else if (j >= oid->aoi_idlen || overflow == -1) {
2821 				data->avb_ostring.aos_slen = 0;
2822 				data->avb_ostring.aos_string = NULL;
2823 				continue;
2824 			}
2825 			if (agentx_object_implied(axo, index->axv_axi))
2826 				data->avb_ostring.aos_slen = oid->aoi_idlen - j;
2827 			else {
2828 				data->avb_ostring.aos_slen = oid->aoi_id[j++];
2829 				if (data->avb_ostring.aos_slen >=
2830 				    AGENTX_OID_MAX_LEN - j) {
2831 					data->avb_ostring.aos_slen = UINT32_MAX;
2832 					overflow = 1;
2833 				}
2834 			}
2835 			if (data->avb_ostring.aos_slen == UINT32_MAX ||
2836 			    data->avb_ostring.aos_slen == 0) {
2837 				data->avb_ostring.aos_string = NULL;
2838 				continue;
2839 			}
2840 			data->avb_ostring.aos_string =
2841 			    malloc(data->avb_ostring.aos_slen + 1);
2842 			if (data->avb_ostring.aos_string == NULL) {
2843 				agentx_log_axg_warn(axg,
2844 				    "Failed to bind string index");
2845 				agentx_varbind_error_type(axv,
2846 				    AX_PDU_ERROR_PROCESSINGERROR, 1);
2847 				return;
2848 			}
2849 			for (k = 0; k < data->avb_ostring.aos_slen; k++, j++) {
2850 				if (j < oid->aoi_idlen && oid->aoi_id[j] > 0xff)
2851 					overflow = 1;
2852 				if (overflow == 1)
2853 					data->avb_ostring.aos_string[k] = 0xff;
2854 				else if (j >= oid->aoi_idlen || overflow == -1)
2855 					data->avb_ostring.aos_string[k] = '\0';
2856 				else
2857 					data->avb_ostring.aos_string[k] =
2858 					    oid->aoi_id[j];
2859 			}
2860 			data->avb_ostring.aos_string[k] = '\0';
2861 			j--;
2862 			break;
2863 		case AX_DATA_TYPE_OID:
2864 			if (overflow == 1) {
2865 				data->avb_oid.aoi_idlen = UINT32_MAX;
2866 				continue;
2867 			} else if (j >= oid->aoi_idlen || overflow == -1) {
2868 				data->avb_oid.aoi_idlen = 0;
2869 				continue;
2870 			}
2871 			if (agentx_object_implied(axo, index->axv_axi))
2872 				data->avb_oid.aoi_idlen = oid->aoi_idlen - j;
2873 			else {
2874 				data->avb_oid.aoi_idlen = oid->aoi_id[j++];
2875 				if (data->avb_oid.aoi_idlen >=
2876 				    AGENTX_OID_MAX_LEN - j) {
2877 					data->avb_oid.aoi_idlen = UINT32_MAX;
2878 					overflow = 1;
2879 				}
2880 			}
2881 			if (data->avb_oid.aoi_idlen == UINT32_MAX ||
2882 			    data->avb_oid.aoi_idlen == 0)
2883 				continue;
2884 			for (k = 0; k < data->avb_oid.aoi_idlen; k++, j++) {
2885 				if (overflow == 1)
2886 					data->avb_oid.aoi_id[k] = UINT32_MAX;
2887 				else if (j >= oid->aoi_idlen || overflow == -1)
2888 					data->avb_oid.aoi_id[k] = 0;
2889 				else
2890 					data->avb_oid.aoi_id[k] =
2891 					    oid->aoi_id[j];
2892 			}
2893 			j--;
2894 			break;
2895 		case AX_DATA_TYPE_IPADDRESS:
2896 			ipaddress = malloc(sizeof(*ipaddress));
2897 			if (ipaddress == NULL) {
2898 				agentx_log_axg_warn(axg,
2899 				    "Failed to bind ipaddress index");
2900 				agentx_varbind_error_type(axv,
2901 				    AX_PDU_ERROR_PROCESSINGERROR, 1);
2902 				return;
2903 			}
2904 			ipbytes = (unsigned char *)ipaddress;
2905 			for (k = 0; k < 4; k++, j++) {
2906 				if (j < oid->aoi_idlen && oid->aoi_id[j] > 255)
2907 					overflow = 1;
2908 				if (overflow == 1)
2909 					ipbytes[k] = 255;
2910 				else if (j >= oid->aoi_idlen || overflow == -1)
2911 					ipbytes[k] = 0;
2912 				else
2913 					ipbytes[k] = oid->aoi_id[j];
2914 			}
2915 			j--;
2916 			data->avb_ostring.aos_slen = sizeof(*ipaddress);
2917 			data->avb_ostring.aos_string =
2918 			    (unsigned char *)ipaddress;
2919 			break;
2920 		default:
2921 #ifdef AX_DEBUG
2922 			agentx_log_axg_fatalx(axg,
2923 			    "%s: unexpected index type", __func__);
2924 #else
2925 			agentx_log_axg_warnx(axg,
2926 			    "%s: unexpected index type", __func__);
2927 			agentx_varbind_error_type(axv,
2928 			    AX_PDU_ERROR_PROCESSINGERROR, 1);
2929 			return;
2930 #endif
2931 		}
2932 	}
2933 	if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET) {
2934 		if (j != oid->aoi_idlen || overflow) {
2935 			agentx_varbind_nosuchinstance(axv);
2936 			return;
2937 		}
2938 	}
2939 
2940 	if (overflow == 1) {
2941 		axv->axv_include = 0;
2942 	} else if (overflow == -1) {
2943 		axv->axv_include = 1;
2944 	} else if (j < oid->aoi_idlen)
2945 		axv->axv_include = 0;
2946 	else if (j > oid->aoi_idlen)
2947 		axv->axv_include = 1;
2948 	if (agentx_varbind_request(axv) == AGENTX_REQUEST_TYPE_GETNEXT &&
2949 	    !dynamic) {
2950 		agentx_varbind_endofmibview(axv);
2951 		return;
2952 	}
2953 
2954 	axo->axo_get(axv);
2955 }
2956 
2957 void
2958 agentx_varbind_integer(struct agentx_varbind *axv, int32_t value)
2959 {
2960 	axv->axv_vb.avb_type = AX_DATA_TYPE_INTEGER;
2961 	axv->axv_vb.avb_data.avb_int32 = value;
2962 
2963 	agentx_varbind_finalize(axv);
2964 }
2965 
2966 void
2967 agentx_varbind_string(struct agentx_varbind *axv, const char *value)
2968 {
2969 	agentx_varbind_nstring(axv, (const unsigned char *)value,
2970 	    strlen(value));
2971 }
2972 
2973 void
2974 agentx_varbind_nstring(struct agentx_varbind *axv,
2975     const unsigned char *value, size_t slen)
2976 {
2977 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(slen);
2978 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
2979 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
2980 		agentx_varbind_error_type(axv,
2981 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
2982 		return;
2983 	}
2984 	axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
2985 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, slen);
2986 	axv->axv_vb.avb_data.avb_ostring.aos_slen = slen;
2987 
2988 	agentx_varbind_finalize(axv);
2989 }
2990 
2991 void
2992 agentx_varbind_printf(struct agentx_varbind *axv, const char *fmt, ...)
2993 {
2994 	va_list ap;
2995 	int r;
2996 
2997 	axv->axv_vb.avb_type = AX_DATA_TYPE_OCTETSTRING;
2998 	va_start(ap, fmt);
2999 	r = vasprintf((char **)&(axv->axv_vb.avb_data.avb_ostring.aos_string),
3000 	    fmt, ap);
3001 	va_end(ap);
3002 	if (r == -1) {
3003 		axv->axv_vb.avb_data.avb_ostring.aos_string = NULL;
3004 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind string");
3005 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
3006 		return;
3007 	}
3008 	axv->axv_vb.avb_data.avb_ostring.aos_slen = r;
3009 
3010 	agentx_varbind_finalize(axv);
3011 }
3012 
3013 void
3014 agentx_varbind_null(struct agentx_varbind *axv)
3015 {
3016 	axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
3017 
3018 	agentx_varbind_finalize(axv);
3019 }
3020 
3021 void
3022 agentx_varbind_oid(struct agentx_varbind *axv, const uint32_t oid[],
3023     size_t oidlen)
3024 {
3025 	const char *errstr;
3026 
3027 	axv->axv_vb.avb_type = AX_DATA_TYPE_OID;
3028 
3029 	if (agentx_oidfill(&(axv->axv_vb.avb_data.avb_oid),
3030 	    oid, oidlen, &errstr) == -1) {
3031 #ifdef AX_DEBUG
3032 		agentx_log_axg_fatalx(axv->axv_axg, "%s: %s", __func__, errstr);
3033 #else
3034 		agentx_log_axg_warnx(axv->axv_axg, "%s: %s", __func__, errstr);
3035 		agentx_varbind_error_type(axv, AX_PDU_ERROR_PROCESSINGERROR, 1);
3036 		return;
3037 #endif
3038 	}
3039 
3040 	agentx_varbind_finalize(axv);
3041 }
3042 
3043 void
3044 agentx_varbind_object(struct agentx_varbind *axv,
3045     struct agentx_object *axo)
3046 {
3047 	agentx_varbind_oid(axv, axo->axo_oid.aoi_id,
3048 	    axo->axo_oid.aoi_idlen);
3049 }
3050 
3051 void
3052 agentx_varbind_index(struct agentx_varbind *axv,
3053     struct agentx_index *axi)
3054 {
3055 	agentx_varbind_oid(axv, axi->axi_vb.avb_oid.aoi_id,
3056 	    axi->axi_vb.avb_oid.aoi_idlen);
3057 }
3058 
3059 
3060 void
3061 agentx_varbind_ipaddress(struct agentx_varbind *axv,
3062     const struct in_addr *value)
3063 {
3064 	axv->axv_vb.avb_type = AX_DATA_TYPE_IPADDRESS;
3065 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(4);
3066 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
3067 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind ipaddress");
3068 		agentx_varbind_error_type(axv,
3069 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
3070 		return;
3071 	}
3072 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, value, 4);
3073 	axv->axv_vb.avb_data.avb_ostring.aos_slen = 4;
3074 
3075 	agentx_varbind_finalize(axv);
3076 }
3077 
3078 void
3079 agentx_varbind_counter32(struct agentx_varbind *axv, uint32_t value)
3080 {
3081 	axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER32;
3082 	axv->axv_vb.avb_data.avb_uint32 = value;
3083 
3084 	agentx_varbind_finalize(axv);
3085 }
3086 
3087 void
3088 agentx_varbind_gauge32(struct agentx_varbind *axv, uint32_t value)
3089 {
3090 	axv->axv_vb.avb_type = AX_DATA_TYPE_GAUGE32;
3091 	axv->axv_vb.avb_data.avb_uint32 = value;
3092 
3093 	agentx_varbind_finalize(axv);
3094 }
3095 
3096 void
3097 agentx_varbind_unsigned32(struct agentx_varbind *axv, uint32_t value)
3098 {
3099 	agentx_varbind_gauge32(axv, value);
3100 }
3101 
3102 void
3103 agentx_varbind_timeticks(struct agentx_varbind *axv, uint32_t value)
3104 {
3105 	axv->axv_vb.avb_type = AX_DATA_TYPE_TIMETICKS;
3106 	axv->axv_vb.avb_data.avb_uint32 = value;
3107 
3108 	agentx_varbind_finalize(axv);
3109 }
3110 
3111 void
3112 agentx_varbind_opaque(struct agentx_varbind *axv, const char *string,
3113     size_t strlen)
3114 {
3115 	axv->axv_vb.avb_type = AX_DATA_TYPE_OPAQUE;
3116 	axv->axv_vb.avb_data.avb_ostring.aos_string = malloc(strlen);
3117 	if (axv->axv_vb.avb_data.avb_ostring.aos_string == NULL) {
3118 		agentx_log_axg_warn(axv->axv_axg, "Couldn't bind opaque");
3119 		agentx_varbind_error_type(axv,
3120 		    AX_PDU_ERROR_PROCESSINGERROR, 1);
3121 		return;
3122 	}
3123 	memcpy(axv->axv_vb.avb_data.avb_ostring.aos_string, string, strlen);
3124 	axv->axv_vb.avb_data.avb_ostring.aos_slen = strlen;
3125 
3126 	agentx_varbind_finalize(axv);
3127 }
3128 
3129 void
3130 agentx_varbind_counter64(struct agentx_varbind *axv, uint64_t value)
3131 {
3132 	axv->axv_vb.avb_type = AX_DATA_TYPE_COUNTER64;
3133 	axv->axv_vb.avb_data.avb_uint64 = value;
3134 
3135 	agentx_varbind_finalize(axv);
3136 }
3137 
3138 void
3139 agentx_varbind_notfound(struct agentx_varbind *axv)
3140 {
3141 	if (axv->axv_indexlen == 0) {
3142 #ifdef AX_DEBUG
3143 		agentx_log_axg_fatalx(axv->axv_axg, "%s invalid call",
3144 		    __func__);
3145 #else
3146 		agentx_log_axg_warnx(axv->axv_axg, "%s invalid call",
3147 		    __func__);
3148 		agentx_varbind_error_type(axv,
3149 		    AX_PDU_ERROR_GENERR, 1);
3150 #endif
3151 	} else if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
3152 		agentx_varbind_nosuchinstance(axv);
3153 	else
3154 		agentx_varbind_endofmibview(axv);
3155 }
3156 
3157 void
3158 agentx_varbind_error(struct agentx_varbind *axv)
3159 {
3160 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 1);
3161 }
3162 
3163 static void
3164 agentx_varbind_error_type(struct agentx_varbind *axv,
3165     enum ax_pdu_error error, int done)
3166 {
3167 	if (axv->axv_error == AX_PDU_ERROR_NOERROR) {
3168 		axv->axv_error = error;
3169 	}
3170 
3171 	if (done) {
3172 		axv->axv_vb.avb_type = AX_DATA_TYPE_NULL;
3173 
3174 		agentx_varbind_finalize(axv);
3175 	}
3176 }
3177 
3178 static void
3179 agentx_varbind_finalize(struct agentx_varbind *axv)
3180 {
3181 	struct agentx_get *axg = axv->axv_axg;
3182 	struct ax_oid oid;
3183 	union ax_data *data;
3184 	size_t i, j;
3185 	int cmp;
3186 
3187 	if (axv->axv_error != AX_PDU_ERROR_NOERROR) {
3188 		bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3189 		    sizeof(axv->axv_start));
3190 		goto done;
3191 	}
3192 	bcopy(&(axv->axv_axo->axo_oid), &oid, sizeof(oid));
3193 	if (axv->axv_indexlen == 0)
3194 		ax_oid_add(&oid, 0);
3195 	for (i = 0; i < axv->axv_indexlen; i++) {
3196 		data = &(axv->axv_index[i].axv_idata);
3197 		switch (axv->axv_index[i].axv_axi->axi_vb.avb_type) {
3198 		case AX_DATA_TYPE_INTEGER:
3199 			if (ax_oid_add(&oid, data->avb_int32) == -1)
3200 				goto fail;
3201 			break;
3202 		case AX_DATA_TYPE_OCTETSTRING:
3203 			if (!agentx_object_implied(axv->axv_axo,
3204 			    axv->axv_index[i].axv_axi)) {
3205 				if (ax_oid_add(&oid,
3206 				    data->avb_ostring.aos_slen) == -1)
3207 					goto fail;
3208 			}
3209 			for (j = 0; j < data->avb_ostring.aos_slen; j++) {
3210 				if (ax_oid_add(&oid,
3211 				    (uint8_t)data->avb_ostring.aos_string[j]) ==
3212 				    -1)
3213 					goto fail;
3214 			}
3215 			break;
3216 		case AX_DATA_TYPE_OID:
3217 			if (!agentx_object_implied(axv->axv_axo,
3218 			    axv->axv_index[i].axv_axi)) {
3219 				if (ax_oid_add(&oid,
3220 				    data->avb_oid.aoi_idlen) == -1)
3221 					goto fail;
3222 			}
3223 			for (j = 0; j < data->avb_oid.aoi_idlen; j++) {
3224 				if (ax_oid_add(&oid,
3225 				    data->avb_oid.aoi_id[j]) == -1)
3226 					goto fail;
3227 			}
3228 			break;
3229 		case AX_DATA_TYPE_IPADDRESS:
3230 			for (j = 0; j < 4; j++) {
3231 				if (ax_oid_add(&oid,
3232 				    data->avb_ostring.aos_string == NULL ? 0 :
3233 				    (uint8_t)data->avb_ostring.aos_string[j]) ==
3234 				    -1)
3235 					goto fail;
3236 			}
3237 			break;
3238 		default:
3239 #ifdef AX_DEBUG
3240 			agentx_log_axg_fatalx(axg,
3241 			    "%s: unsupported index type", __func__);
3242 #else
3243 			bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3244 			    sizeof(axv->axv_start));
3245 			axv->axv_error = AX_PDU_ERROR_PROCESSINGERROR;
3246 			agentx_object_unlock(axv->axv_axo);
3247 			agentx_get_finalize(axv->axv_axg);
3248 			return;
3249 #endif
3250 		}
3251 	}
3252 	cmp = ax_oid_cmp(&(axv->axv_vb.avb_oid), &oid);
3253 	if ((agentx_varbind_request(axv) == AGENTX_REQUEST_TYPE_GETNEXT &&
3254 	    cmp >= 0) || cmp > 0) {
3255 #ifdef AX_DEBUG
3256 		agentx_log_axg_fatalx(axg, "indices not incremented");
3257 #else
3258 		agentx_log_axg_warnx(axg, "indices not incremented");
3259 		bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3260 		    sizeof(axv->axv_start));
3261 		axv->axv_error = AX_PDU_ERROR_GENERR;
3262 #endif
3263 	} else
3264 		bcopy(&oid, &(axv->axv_vb.avb_oid), sizeof(oid));
3265 done:
3266 	agentx_object_unlock(axv->axv_axo);
3267 	agentx_get_finalize(axv->axv_axg);
3268 	return;
3269 
3270 fail:
3271 	agentx_log_axg_warnx(axg, "oid too large");
3272 	bcopy(&(axv->axv_start), &(axv->axv_vb.avb_oid),
3273 	    sizeof(axv->axv_start));
3274 	axv->axv_error = AX_PDU_ERROR_GENERR;
3275 	agentx_object_unlock(axv->axv_axo);
3276 	agentx_get_finalize(axv->axv_axg);
3277 }
3278 
3279 static void
3280 agentx_varbind_nosuchobject(struct agentx_varbind *axv)
3281 {
3282 	axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHOBJECT;
3283 
3284 	if (axv->axv_axo != NULL)
3285 		agentx_object_unlock(axv->axv_axo);
3286 	agentx_get_finalize(axv->axv_axg);
3287 }
3288 
3289 static void
3290 agentx_varbind_nosuchinstance(struct agentx_varbind *axv)
3291 {
3292 	axv->axv_vb.avb_type = AX_DATA_TYPE_NOSUCHINSTANCE;
3293 
3294 	if (axv->axv_axo != NULL)
3295 		agentx_object_unlock(axv->axv_axo);
3296 	agentx_get_finalize(axv->axv_axg);
3297 }
3298 
3299 static void
3300 agentx_varbind_endofmibview(struct agentx_varbind *axv)
3301 {
3302 	struct agentx_object *axo;
3303 	struct ax_varbind *vb;
3304 	struct agentx_varbind_index *index;
3305 	size_t i;
3306 
3307 #ifdef AX_DEBUG
3308 	if (axv->axv_axg->axg_type != AX_PDU_TYPE_GETNEXT &&
3309 	    axv->axv_axg->axg_type != AX_PDU_TYPE_GETBULK)
3310 		agentx_log_axg_fatalx(axv->axv_axg,
3311 		    "%s: invalid request type", __func__);
3312 #endif
3313 
3314 	if (axv->axv_axo != NULL &&
3315 	    (axo = RB_NEXT(axc_objects, &(axc->axc_objects),
3316 	    axv->axv_axo)) != NULL &&
3317 	    ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) < 0) {
3318 		bcopy(&(axo->axo_oid), &(axv->axv_vb.avb_oid),
3319 		    sizeof(axo->axo_oid));
3320 		axv->axv_include = 1;
3321 		for (i = 0; i < axv->axv_indexlen; i++) {
3322 			index = &(axv->axv_index[i]);
3323 			vb = &(index->axv_axi->axi_vb);
3324 			if (vb->avb_type == AX_DATA_TYPE_OCTETSTRING ||
3325 			    vb->avb_type == AX_DATA_TYPE_IPADDRESS)
3326 				free(index->axv_idata.avb_ostring.aos_string);
3327 		}
3328 		bzero(&(axv->axv_index), sizeof(axv->axv_index));
3329 		agentx_object_unlock(axv->axv_axo);
3330 		agentx_varbind_start(axv);
3331 		return;
3332 	}
3333 
3334 	axv->axv_vb.avb_type = AX_DATA_TYPE_ENDOFMIBVIEW;
3335 
3336 	if (axv->axv_axo != NULL)
3337 		agentx_object_unlock(axv->axv_axo);
3338 	agentx_get_finalize(axv->axv_axg);
3339 }
3340 
3341 enum agentx_request_type
3342 agentx_varbind_request(struct agentx_varbind *axv)
3343 {
3344 	if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET)
3345 		return AGENTX_REQUEST_TYPE_GET;
3346 	if (axv->axv_include)
3347 		return AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE;
3348 	return AGENTX_REQUEST_TYPE_GETNEXT;
3349 }
3350 
3351 struct agentx_object *
3352 agentx_varbind_get_object(struct agentx_varbind *axv)
3353 {
3354 	return axv->axv_axo;
3355 }
3356 
3357 int32_t
3358 agentx_varbind_get_index_integer(struct agentx_varbind *axv,
3359     struct agentx_index *axi)
3360 {
3361 	size_t i;
3362 
3363 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
3364 #ifdef AX_DEBUG
3365 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3366 #else
3367 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3368 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3369 		return 0;
3370 #endif
3371 	}
3372 
3373 	for (i = 0; i < axv->axv_indexlen; i++) {
3374 		if (axv->axv_index[i].axv_axi == axi)
3375 			return axv->axv_index[i].axv_idata.avb_int32;
3376 	}
3377 #ifdef AX_DEBUG
3378 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3379 #else
3380 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3381 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3382 	return 0;
3383 #endif
3384 }
3385 
3386 const unsigned char *
3387 agentx_varbind_get_index_string(struct agentx_varbind *axv,
3388     struct agentx_index *axi, size_t *slen, int *implied)
3389 {
3390 	struct agentx_varbind_index *index;
3391 	size_t i;
3392 
3393 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
3394 #ifdef AX_DEBUG
3395 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3396 #else
3397 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3398 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3399 		*slen = 0;
3400 		*implied = 0;
3401 		return NULL;
3402 #endif
3403 	}
3404 
3405 	for (i = 0; i < axv->axv_indexlen; i++) {
3406 		if (axv->axv_index[i].axv_axi == axi) {
3407 			index = &(axv->axv_index[i]);
3408 			*slen = index->axv_idata.avb_ostring.aos_slen;
3409 			*implied = agentx_object_implied(axv->axv_axo, axi);
3410 			return index->axv_idata.avb_ostring.aos_string;
3411 		}
3412 	}
3413 
3414 #ifdef AX_DEBUG
3415 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3416 #else
3417 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3418 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3419 	*slen = 0;
3420 	*implied = 0;
3421 	return NULL;
3422 #endif
3423 }
3424 
3425 const uint32_t *
3426 agentx_varbind_get_index_oid(struct agentx_varbind *axv,
3427     struct agentx_index *axi, size_t *oidlen, int *implied)
3428 {
3429 	struct agentx_varbind_index *index;
3430 	size_t i;
3431 
3432 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
3433 #ifdef AX_DEBUG
3434 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3435 #else
3436 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3437 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3438 		*oidlen = 0;
3439 		*implied = 0;
3440 		return NULL;
3441 #endif
3442 	}
3443 
3444 	for (i = 0; i < axv->axv_indexlen; i++) {
3445 		if (axv->axv_index[i].axv_axi == axi) {
3446 			index = &(axv->axv_index[i]);
3447 			*oidlen = index->axv_idata.avb_oid.aoi_idlen;
3448 			*implied = agentx_object_implied(axv->axv_axo, axi);
3449 			return index->axv_idata.avb_oid.aoi_id;
3450 		}
3451 	}
3452 
3453 #ifdef AX_DEBUG
3454 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3455 #else
3456 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3457 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3458 	*oidlen = 0;
3459 	*implied = 0;
3460 	return NULL;
3461 #endif
3462 }
3463 
3464 const struct in_addr *
3465 agentx_varbind_get_index_ipaddress(struct agentx_varbind *axv,
3466     struct agentx_index *axi)
3467 {
3468 	static struct in_addr nuladdr = {0};
3469 	struct agentx_varbind_index *index;
3470 	size_t i;
3471 
3472 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
3473 #ifdef AX_DEBUG
3474 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3475 #else
3476 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3477 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3478 		return NULL;
3479 #endif
3480 	}
3481 
3482 	for (i = 0; i < axv->axv_indexlen; i++) {
3483 		if (axv->axv_index[i].axv_axi == axi) {
3484 			index = &(axv->axv_index[i]);
3485 			if (index->axv_idata.avb_ostring.aos_string == NULL)
3486 				return &nuladdr;
3487 			return (struct in_addr *)
3488 			    index->axv_idata.avb_ostring.aos_string;
3489 		}
3490 	}
3491 
3492 #ifdef AX_DEBUG
3493 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3494 #else
3495 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3496 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3497 	return NULL;
3498 #endif
3499 }
3500 
3501 void
3502 agentx_varbind_set_index_integer(struct agentx_varbind *axv,
3503     struct agentx_index *axi, int32_t value)
3504 {
3505 	size_t i;
3506 
3507 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_INTEGER) {
3508 #ifdef AX_DEBUG
3509 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3510 #else
3511 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3512 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3513 		return;
3514 #endif
3515 	}
3516 
3517 	if (value < 0) {
3518 #ifdef AX_DEBUG
3519 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index value");
3520 #else
3521 		agentx_log_axg_warnx(axv->axv_axg, "invalid index value");
3522 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3523 		return;
3524 #endif
3525 	}
3526 
3527 	for (i = 0; i < axv->axv_indexlen; i++) {
3528 		if (axv->axv_index[i].axv_axi == axi) {
3529 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3530 			    axv->axv_index[i].axv_idata.avb_int32 != value) {
3531 #ifdef AX_DEBUG
3532 				agentx_log_axg_fatalx(axv->axv_axg,
3533 				    "can't change index on GET");
3534 #else
3535 				agentx_log_axg_warnx(axv->axv_axg,
3536 				    "can't change index on GET");
3537 				agentx_varbind_error_type(axv,
3538 				    AX_PDU_ERROR_GENERR, 0);
3539 				return;
3540 #endif
3541 			}
3542 			axv->axv_index[i].axv_idata.avb_int32 = value;
3543 			return;
3544 		}
3545 	}
3546 #ifdef AX_DEBUG
3547 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3548 #else
3549 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3550 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3551 #endif
3552 }
3553 
3554 void
3555 agentx_varbind_set_index_string(struct agentx_varbind *axv,
3556     struct agentx_index *axi, const char *value)
3557 {
3558 	agentx_varbind_set_index_nstring(axv, axi,
3559 	    (const unsigned char *)value, strlen(value));
3560 }
3561 
3562 void
3563 agentx_varbind_set_index_nstring(struct agentx_varbind *axv,
3564     struct agentx_index *axi, const unsigned char *value, size_t slen)
3565 {
3566 	struct ax_ostring *curvalue;
3567 	unsigned char *nstring;
3568 	size_t i;
3569 
3570 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OCTETSTRING) {
3571 #ifdef AX_DEBUG
3572 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3573 #else
3574 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3575 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3576 		return;
3577 #endif
3578 	}
3579 
3580 	for (i = 0; i < axv->axv_indexlen; i++) {
3581 		if (axv->axv_index[i].axv_axi == axi) {
3582 			if (axi->axi_vb.avb_data.avb_ostring.aos_slen != 0 &&
3583 			    axi->axi_vb.avb_data.avb_ostring.aos_slen != slen) {
3584 #ifdef AX_DEBUG
3585 				agentx_log_axg_fatalx(axv->axv_axg,
3586 				    "invalid string length on explicit length "
3587 				    "string");
3588 #else
3589 				agentx_log_axg_warnx(axv->axv_axg,
3590 				    "invalid string length on explicit length "
3591 				    "string");
3592 				agentx_varbind_error_type(axv,
3593 				    AX_PDU_ERROR_GENERR, 0);
3594 				return;
3595 #endif
3596 			}
3597 			curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
3598 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3599 			    (curvalue->aos_slen != slen ||
3600 			    memcmp(curvalue->aos_string, value, slen) != 0)) {
3601 #ifdef AX_DEBUG
3602 				agentx_log_axg_fatalx(axv->axv_axg,
3603 				    "can't change index on GET");
3604 #else
3605 				agentx_log_axg_warnx(axv->axv_axg,
3606 				    "can't change index on GET");
3607 				agentx_varbind_error_type(axv,
3608 				    AX_PDU_ERROR_GENERR, 0);
3609 				return;
3610 #endif
3611 			}
3612 			if ((nstring = recallocarray(curvalue->aos_string,
3613 			    curvalue->aos_slen + 1, slen + 1, 1)) == NULL) {
3614 				agentx_log_axg_warn(axv->axv_axg,
3615 				    "Failed to bind string index");
3616 				agentx_varbind_error_type(axv,
3617 				    AX_PDU_ERROR_PROCESSINGERROR, 0);
3618 				return;
3619 			}
3620 			curvalue->aos_string = nstring;
3621 			memcpy(nstring, value, slen);
3622 			curvalue->aos_slen = slen;
3623 			return;
3624 		}
3625 	}
3626 #ifdef AX_DEBUG
3627 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3628 #else
3629 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3630 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3631 #endif
3632 }
3633 
3634 void
3635 agentx_varbind_set_index_oid(struct agentx_varbind *axv,
3636     struct agentx_index *axi, const uint32_t *value, size_t oidlen)
3637 {
3638 	struct ax_oid *curvalue, oid;
3639 	const char *errstr;
3640 	size_t i;
3641 
3642 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_OID) {
3643 #ifdef AX_DEBUG
3644 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3645 #else
3646 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3647 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3648 		return;
3649 #endif
3650 	}
3651 
3652 	for (i = 0; i < axv->axv_indexlen; i++) {
3653 		if (axv->axv_index[i].axv_axi == axi) {
3654 			if (axi->axi_vb.avb_data.avb_oid.aoi_idlen != 0 &&
3655 			    axi->axi_vb.avb_data.avb_oid.aoi_idlen != oidlen) {
3656 #ifdef AX_DEBUG
3657 				agentx_log_axg_fatalx(axv->axv_axg,
3658 				    "invalid oid length on explicit length "
3659 				    "oid");
3660 #else
3661 				agentx_log_axg_warnx(axv->axv_axg,
3662 				    "invalid oid length on explicit length "
3663 				    "oid");
3664 				agentx_varbind_error_type(axv,
3665 				    AX_PDU_ERROR_GENERR, 0);
3666 				return;
3667 #endif
3668 			}
3669 			curvalue = &(axv->axv_index[i].axv_idata.avb_oid);
3670 			if (agentx_oidfill(&oid, value,
3671 			    oidlen, &errstr) == -1) {
3672 #ifdef AX_DEBUG
3673 				agentx_log_axg_fatalx(axv->axv_axg, "%s: %s",
3674 				    __func__, errstr);
3675 #else
3676 				agentx_log_axg_warnx(axv->axv_axg, "%s: %s",
3677 				     __func__, errstr);
3678 				agentx_varbind_error_type(axv,
3679 				     AX_PDU_ERROR_PROCESSINGERROR, 1);
3680 				return;
3681 #endif
3682 			}
3683 
3684 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3685 			    ax_oid_cmp(&oid, curvalue) != 0) {
3686 #ifdef AX_DEBUG
3687 				agentx_log_axg_fatalx(axv->axv_axg,
3688 				    "can't change index on GET");
3689 #else
3690 				agentx_log_axg_warnx(axv->axv_axg,
3691 				    "can't change index on GET");
3692 				agentx_varbind_error_type(axv,
3693 				    AX_PDU_ERROR_GENERR, 0);
3694 				return;
3695 #endif
3696 			}
3697 
3698 			*curvalue = oid;
3699 			return;
3700 		}
3701 	}
3702 #ifdef AX_DEBUG
3703 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3704 #else
3705 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3706 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3707 #endif
3708 }
3709 
3710 void
3711 agentx_varbind_set_index_object(struct agentx_varbind *axv,
3712     struct agentx_index *axi, struct agentx_object *axo)
3713 {
3714 	agentx_varbind_set_index_oid(axv, axi, axo->axo_oid.aoi_id,
3715 	    axo->axo_oid.aoi_idlen);
3716 }
3717 
3718 void
3719 agentx_varbind_set_index_ipaddress(struct agentx_varbind *axv,
3720     struct agentx_index *axi, const struct in_addr *addr)
3721 {
3722 	struct ax_ostring *curvalue;
3723 	size_t i;
3724 
3725 	if (axi->axi_vb.avb_type != AX_DATA_TYPE_IPADDRESS) {
3726 #ifdef AX_DEBUG
3727 		agentx_log_axg_fatalx(axv->axv_axg, "invalid index type");
3728 #else
3729 		agentx_log_axg_warnx(axv->axv_axg, "invalid index type");
3730 		agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3731 		return;
3732 #endif
3733 	}
3734 
3735 	for (i = 0; i < axv->axv_indexlen; i++) {
3736 		if (axv->axv_index[i].axv_axi == axi) {
3737 			curvalue = &(axv->axv_index[i].axv_idata.avb_ostring);
3738 			if (curvalue->aos_string == NULL)
3739 				curvalue->aos_string = calloc(1, sizeof(*addr));
3740 			if (curvalue->aos_string == NULL) {
3741 				agentx_log_axg_warn(axv->axv_axg,
3742 				    "Failed to bind ipaddress index");
3743 				agentx_varbind_error_type(axv,
3744 				    AX_PDU_ERROR_PROCESSINGERROR, 0);
3745 				return;
3746 			}
3747 			if (axv->axv_axg->axg_type == AX_PDU_TYPE_GET &&
3748 			    memcmp(addr, curvalue->aos_string,
3749 			    sizeof(*addr)) != 0) {
3750 #ifdef AX_DEBUG
3751 				agentx_log_axg_fatalx(axv->axv_axg,
3752 				    "can't change index on GET");
3753 #else
3754 				agentx_log_axg_warnx(axv->axv_axg,
3755 				    "can't change index on GET");
3756 				agentx_varbind_error_type(axv,
3757 				    AX_PDU_ERROR_GENERR, 0);
3758 				return;
3759 #endif
3760 			}
3761 			bcopy(addr, curvalue->aos_string, sizeof(*addr));
3762 			return;
3763 		}
3764 	}
3765 #ifdef AX_DEBUG
3766 	agentx_log_axg_fatalx(axv->axv_axg, "invalid index");
3767 #else
3768 	agentx_log_axg_warnx(axv->axv_axg, "invalid index");
3769 	agentx_varbind_error_type(axv, AX_PDU_ERROR_GENERR, 0);
3770 #endif
3771 }
3772 
3773 static int
3774 agentx_request(struct agentx *ax, uint32_t packetid,
3775     int (*cb)(struct ax_pdu *, void *), void *cookie)
3776 {
3777 	struct agentx_request *axr;
3778 
3779 #ifdef AX_DEBUG
3780 	if (ax->ax_ax->ax_wblen == 0)
3781 		agentx_log_ax_fatalx(ax, "%s: no data to be written",
3782 		    __func__);
3783 #endif
3784 
3785 	if ((axr = calloc(1, sizeof(*axr))) == NULL) {
3786 		agentx_log_ax_warn(ax, "couldn't create request context");
3787 		agentx_reset(ax);
3788 		return -1;
3789 	}
3790 
3791 	axr->axr_packetid = packetid;
3792 	axr->axr_cb = cb;
3793 	axr->axr_cookie = cookie;
3794 	if (RB_INSERT(ax_requests, &(ax->ax_requests), axr) != NULL) {
3795 #ifdef AX_DEBUG
3796 		agentx_log_ax_fatalx(ax, "%s: duplicate packetid", __func__);
3797 #else
3798 		agentx_log_ax_warnx(ax, "%s: duplicate packetid", __func__);
3799 		free(axr);
3800 		agentx_reset(ax);
3801 		return -1;
3802 #endif
3803 	}
3804 
3805 	agentx_wantwrite(ax, ax->ax_fd);
3806 	return 0;
3807 }
3808 
3809 static int
3810 agentx_request_cmp(struct agentx_request *r1,
3811     struct agentx_request *r2)
3812 {
3813 	return r1->axr_packetid < r2->axr_packetid ? -1 :
3814 	    r1->axr_packetid > r2->axr_packetid;
3815 }
3816 
3817 static int
3818 agentx_strcat(char **dst, const char *src)
3819 {
3820 	char *tmp;
3821 	size_t dstlen = 0, buflen = 0, srclen, nbuflen;
3822 
3823 	if (*dst != NULL) {
3824 		dstlen = strlen(*dst);
3825 		buflen = ((dstlen / 512) + 1) * 512;
3826 	}
3827 
3828 	srclen = strlen(src);
3829 	if (*dst == NULL || dstlen + srclen > buflen) {
3830 		nbuflen = (((dstlen + srclen) / 512) + 1) * 512;
3831 		tmp = recallocarray(*dst, buflen, nbuflen, sizeof(*tmp));
3832 		if (tmp == NULL)
3833 			return -1;
3834 		*dst = tmp;
3835 		buflen = nbuflen;
3836 	}
3837 
3838 	(void)strlcat(*dst, src, buflen);
3839 	return 0;
3840 }
3841 
3842 static int
3843 agentx_oidfill(struct ax_oid *oid, const uint32_t oidval[], size_t oidlen,
3844     const char **errstr)
3845 {
3846 	size_t i;
3847 
3848 	if (oidlen < AGENTX_OID_MIN_LEN) {
3849 		*errstr = "oidlen < 2";
3850 		errno = EINVAL;
3851 		return -1;
3852 	}
3853 	if (oidlen > AGENTX_OID_MAX_LEN) {
3854 		*errstr = "oidlen > 128";
3855 		errno = EINVAL;
3856 		return -1;
3857 	}
3858 
3859 	for (i = 0; i < oidlen; i++)
3860 		oid->aoi_id[i] = oidval[i];
3861 	oid->aoi_idlen = oidlen;
3862 	return 0;
3863 }
3864 
3865 void
3866 agentx_read(struct agentx *ax)
3867 {
3868 	struct agentx_session *axs;
3869 	struct agentx_context *axc;
3870 	struct agentx_request axr_search, *axr;
3871 	struct ax_pdu *pdu;
3872 	int error;
3873 
3874 	if ((pdu = ax_recv(ax->ax_ax)) == NULL) {
3875 		if (errno == EAGAIN)
3876 			return;
3877 		agentx_log_ax_warn(ax, "lost connection");
3878 		agentx_reset(ax);
3879 		return;
3880 	}
3881 
3882 	TAILQ_FOREACH(axs, &(ax->ax_sessions), axs_ax_sessions) {
3883 		if (axs->axs_id == pdu->ap_header.aph_sessionid)
3884 			break;
3885 		if (axs->axs_cstate == AX_CSTATE_WAITOPEN &&
3886 		    axs->axs_packetid == pdu->ap_header.aph_packetid)
3887 			break;
3888 	}
3889 	if (axs == NULL) {
3890 		agentx_log_ax_warnx(ax, "received unexpected session: %d",
3891 		    pdu->ap_header.aph_sessionid);
3892 		ax_pdu_free(pdu);
3893 		agentx_reset(ax);
3894 		return;
3895 	}
3896 	TAILQ_FOREACH(axc, &(axs->axs_contexts), axc_axs_contexts) {
3897 		if ((pdu->ap_header.aph_flags &
3898 		    AX_PDU_FLAG_NON_DEFAULT_CONTEXT) == 0 &&
3899 		    axc->axc_name_default == 1)
3900 			break;
3901 		if (pdu->ap_header.aph_flags &
3902 		    AX_PDU_FLAG_NON_DEFAULT_CONTEXT &&
3903 		    axc->axc_name_default == 0 &&
3904 		    pdu->ap_context.aos_slen == axc->axc_name.aos_slen &&
3905 		    memcmp(pdu->ap_context.aos_string,
3906 		    axc->axc_name.aos_string, axc->axc_name.aos_slen) == 0)
3907 			break;
3908 	}
3909 	if (pdu->ap_header.aph_type != AX_PDU_TYPE_RESPONSE) {
3910 		if (axc == NULL) {
3911 			agentx_log_ax_warnx(ax, "%s: invalid context",
3912 			    pdu->ap_context.aos_string);
3913 			ax_pdu_free(pdu);
3914 			agentx_reset(ax);
3915 			return;
3916 		}
3917 	}
3918 
3919 	switch (pdu->ap_header.aph_type) {
3920 	case AX_PDU_TYPE_GET:
3921 	case AX_PDU_TYPE_GETNEXT:
3922 	case AX_PDU_TYPE_GETBULK:
3923 		agentx_get_start(axc, pdu);
3924 		break;
3925 	/* Add stubs for set functions */
3926 	case AX_PDU_TYPE_TESTSET:
3927 	case AX_PDU_TYPE_COMMITSET:
3928 	case AX_PDU_TYPE_UNDOSET:
3929 		if (pdu->ap_header.aph_type == AX_PDU_TYPE_TESTSET)
3930 			error = AX_PDU_ERROR_NOTWRITABLE;
3931 		else if (pdu->ap_header.aph_type == AX_PDU_TYPE_COMMITSET)
3932 			error = AX_PDU_ERROR_COMMITFAILED;
3933 		else
3934 			error = AX_PDU_ERROR_UNDOFAILED;
3935 
3936 		agentx_log_axc_debug(axc, "unsupported call: %s",
3937 		    ax_pdutype2string(pdu->ap_header.aph_type));
3938 		if (ax_response(ax->ax_ax, axs->axs_id,
3939 		    pdu->ap_header.aph_transactionid,
3940 		    pdu->ap_header.aph_packetid,
3941 		    axc == NULL ? NULL : AGENTX_CONTEXT_CTX(axc),
3942 		    0, error, 1, NULL, 0) == -1)
3943 			agentx_log_axc_warn(axc,
3944 			    "transaction: %u packetid: %u: failed to send "
3945 			    "reply", pdu->ap_header.aph_transactionid,
3946 			    pdu->ap_header.aph_packetid);
3947 		if (ax->ax_ax->ax_wblen > 0)
3948 			agentx_wantwrite(ax, ax->ax_fd);
3949 		break;
3950 	case AX_PDU_TYPE_CLEANUPSET:
3951 		agentx_log_ax_debug(ax, "unsupported call: %s",
3952 		    ax_pdutype2string(pdu->ap_header.aph_type));
3953 		break;
3954 	case AX_PDU_TYPE_RESPONSE:
3955 		axr_search.axr_packetid = pdu->ap_header.aph_packetid;
3956 		axr = RB_FIND(ax_requests, &(ax->ax_requests), &axr_search);
3957 		if (axr == NULL) {
3958 			if (axc == NULL)
3959 				agentx_log_ax_warnx(ax, "received "
3960 				    "response on non-request");
3961 			else
3962 				agentx_log_axc_warnx(axc, "received "
3963 				    "response on non-request");
3964 			break;
3965 		}
3966 		if (axc != NULL && pdu->ap_payload.ap_response.ap_error == 0) {
3967 			axc->axc_sysuptime =
3968 			    pdu->ap_payload.ap_response.ap_uptime;
3969 			(void) clock_gettime(CLOCK_MONOTONIC,
3970 			    &(axc->axc_sysuptimespec));
3971 		}
3972 		RB_REMOVE(ax_requests, &(ax->ax_requests), axr);
3973 		(void) axr->axr_cb(pdu, axr->axr_cookie);
3974 		free(axr);
3975 		break;
3976 	default:
3977 		if (axc == NULL)
3978 			agentx_log_ax_warnx(ax, "unsupported call: %s",
3979 			    ax_pdutype2string(pdu->ap_header.aph_type));
3980 		else
3981 			agentx_log_axc_warnx(axc, "unsupported call: %s",
3982 			    ax_pdutype2string(pdu->ap_header.aph_type));
3983 		agentx_reset(ax);
3984 		break;
3985 	}
3986 	ax_pdu_free(pdu);
3987 }
3988 
3989 void
3990 agentx_write(struct agentx *ax)
3991 {
3992 	ssize_t send;
3993 
3994 	if ((send = ax_send(ax->ax_ax)) == -1) {
3995 		if (errno == EAGAIN) {
3996 			agentx_wantwrite(ax, ax->ax_fd);
3997 			return;
3998 		}
3999 		agentx_log_ax_warn(ax, "lost connection");
4000 		agentx_reset(ax);
4001 		return;
4002 	}
4003 	if (send > 0)
4004 		agentx_wantwrite(ax, ax->ax_fd);
4005 }
4006 
4007 RB_GENERATE_STATIC(ax_requests, agentx_request, axr_ax_requests,
4008     agentx_request_cmp)
4009 RB_GENERATE_STATIC(axc_objects, agentx_object, axo_axc_objects,
4010     agentx_object_cmp)
4011