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