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