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