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