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