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