jcs's openbsd hax
openbsd
at jcs 4149 lines 111 kB view raw
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)