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