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