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