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