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