| File: | src/lib/libagentx/ax.c |
| Warning: | line 1034, column 15 Array access (via field 'ax_packetids') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ax.c,v 1.8 2021/10/24 17:43:38 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 <sys/socket.h> | |||
| 18 | ||||
| 19 | #include <arpa/inet.h> | |||
| 20 | ||||
| 21 | #include <ctype.h> | |||
| 22 | #include <endian.h> | |||
| 23 | #include <errno(*__errno()).h> | |||
| 24 | #include <inttypes.h> | |||
| 25 | #include <stdlib.h> | |||
| 26 | #include <stdint.h> | |||
| 27 | #include <stdio.h> | |||
| 28 | #include <string.h> | |||
| 29 | #include <strings.h> | |||
| 30 | #include <unistd.h> | |||
| 31 | ||||
| 32 | #include "ax.h" | |||
| 33 | ||||
| 34 | #define AX_PDU_HEADER20 20 | |||
| 35 | ||||
| 36 | static int ax_pdu_need(struct ax *, size_t); | |||
| 37 | static int ax_pdu_header(struct ax *, | |||
| 38 | enum ax_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t, | |||
| 39 | struct ax_ostring *); | |||
| 40 | static uint32_t ax_packetid(struct ax *); | |||
| 41 | static uint32_t ax_pdu_queue(struct ax *); | |||
| 42 | static int ax_pdu_add_uint16(struct ax *, uint16_t); | |||
| 43 | static int ax_pdu_add_uint32(struct ax *, uint32_t); | |||
| 44 | static int ax_pdu_add_uint64(struct ax *, uint64_t); | |||
| 45 | static int ax_pdu_add_oid(struct ax *, struct ax_oid *, int); | |||
| 46 | static int ax_pdu_add_str(struct ax *, struct ax_ostring *); | |||
| 47 | static int ax_pdu_add_varbindlist( struct ax *, struct ax_varbind *, | |||
| 48 | size_t); | |||
| 49 | static uint16_t ax_pdutoh16(struct ax_pdu_header *, uint8_t *); | |||
| 50 | static uint32_t ax_pdutoh32(struct ax_pdu_header *, uint8_t *); | |||
| 51 | static uint64_t ax_pdutoh64(struct ax_pdu_header *, uint8_t *); | |||
| 52 | static ssize_t ax_pdutooid(struct ax_pdu_header *, struct ax_oid *, | |||
| 53 | uint8_t *, size_t); | |||
| 54 | static ssize_t ax_pdutoostring(struct ax_pdu_header *, | |||
| 55 | struct ax_ostring *, uint8_t *, size_t); | |||
| 56 | static ssize_t ax_pdutovarbind(struct ax_pdu_header *, | |||
| 57 | struct ax_varbind *, uint8_t *, size_t); | |||
| 58 | ||||
| 59 | struct ax * | |||
| 60 | ax_new(int fd) | |||
| 61 | { | |||
| 62 | struct ax *ax; | |||
| 63 | ||||
| 64 | if (fd == -1) { | |||
| 65 | errno(*__errno()) = EINVAL22; | |||
| 66 | return NULL((void *)0); | |||
| 67 | } | |||
| 68 | ||||
| 69 | if ((ax = calloc(1, sizeof(*ax))) == NULL((void *)0)) | |||
| 70 | return NULL((void *)0); | |||
| 71 | ax->ax_fd = fd; | |||
| 72 | ax->ax_rbsize = 512; | |||
| 73 | if ((ax->ax_rbuf = malloc(ax->ax_rbsize)) == NULL((void *)0)) | |||
| 74 | goto fail; | |||
| 75 | ax->ax_byteorder = AX_BYTE_ORDER_NATIVEAX_BYTE_ORDER_LE; | |||
| 76 | ||||
| 77 | return ax; | |||
| 78 | ||||
| 79 | fail: | |||
| 80 | free(ax); | |||
| 81 | return NULL((void *)0); | |||
| 82 | } | |||
| 83 | ||||
| 84 | void | |||
| 85 | ax_free(struct ax *ax) | |||
| 86 | { | |||
| 87 | if (ax == NULL((void *)0)) | |||
| 88 | return; | |||
| 89 | close(ax->ax_fd); | |||
| 90 | free(ax->ax_rbuf); | |||
| 91 | free(ax->ax_wbuf); | |||
| 92 | free(ax->ax_packetids); | |||
| 93 | free(ax); | |||
| 94 | } | |||
| 95 | ||||
| 96 | struct ax_pdu * | |||
| 97 | ax_recv(struct ax *ax) | |||
| 98 | { | |||
| 99 | struct ax_pdu *pdu; | |||
| 100 | struct ax_pdu_header header; | |||
| 101 | struct ax_pdu_response *response; | |||
| 102 | struct ax_varbind *varbind; | |||
| 103 | struct ax_pdu_searchrangelist *srl = NULL((void *)0); | |||
| 104 | struct ax_pdu_varbindlist *vbl; | |||
| 105 | struct ax_searchrange *sr; | |||
| 106 | size_t rbsize, packetidx = 0, i, rawlen; | |||
| 107 | ssize_t nread; | |||
| 108 | uint8_t *u8; | |||
| 109 | uint8_t *rbuf; | |||
| 110 | int found; | |||
| 111 | ||||
| 112 | /* Only read a single packet at a time to make sure libevent triggers */ | |||
| 113 | if (ax->ax_rblen < AX_PDU_HEADER20) { | |||
| 114 | if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen, | |||
| 115 | AX_PDU_HEADER20 - ax->ax_rblen)) == 0) { | |||
| 116 | errno(*__errno()) = ECONNRESET54; | |||
| 117 | return NULL((void *)0); | |||
| 118 | } | |||
| 119 | if (nread == -1) | |||
| 120 | return NULL((void *)0); | |||
| 121 | ax->ax_rblen += nread; | |||
| 122 | if (ax->ax_rblen < AX_PDU_HEADER20) { | |||
| 123 | errno(*__errno()) = EAGAIN35; | |||
| 124 | return NULL((void *)0); | |||
| 125 | } | |||
| 126 | } | |||
| 127 | u8 = ax->ax_rbuf; | |||
| 128 | header.aph_version = *u8++; | |||
| 129 | header.aph_type = *u8++; | |||
| 130 | header.aph_flags = *u8++; | |||
| 131 | u8++; | |||
| 132 | header.aph_sessionid = ax_pdutoh32(&header, u8); | |||
| 133 | u8 += 4; | |||
| 134 | header.aph_transactionid = ax_pdutoh32(&header, u8); | |||
| 135 | u8 += 4; | |||
| 136 | header.aph_packetid = ax_pdutoh32(&header, u8); | |||
| 137 | u8 += 4; | |||
| 138 | header.aph_plength = ax_pdutoh32(&header, u8); | |||
| 139 | ||||
| 140 | if (header.aph_version != 1) { | |||
| 141 | errno(*__errno()) = EPROTO95; | |||
| 142 | return NULL((void *)0); | |||
| 143 | } | |||
| 144 | if (ax->ax_rblen < AX_PDU_HEADER20 + header.aph_plength) { | |||
| 145 | if (AX_PDU_HEADER20 + header.aph_plength > ax->ax_rbsize) { | |||
| 146 | rbsize = (((AX_PDU_HEADER20 + header.aph_plength) | |||
| 147 | / 512) + 1) * 512; | |||
| 148 | if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize, | |||
| 149 | rbsize, sizeof(*rbuf))) == NULL((void *)0)) | |||
| 150 | return NULL((void *)0); | |||
| 151 | ax->ax_rbsize = rbsize; | |||
| 152 | ax->ax_rbuf = rbuf; | |||
| 153 | } | |||
| 154 | nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen, | |||
| 155 | header.aph_plength - (ax->ax_rblen - AX_PDU_HEADER20)); | |||
| 156 | if (nread == 0) | |||
| 157 | errno(*__errno()) = ECONNRESET54; | |||
| 158 | if (nread <= 0) | |||
| 159 | return NULL((void *)0); | |||
| 160 | ax->ax_rblen += nread; | |||
| 161 | if (ax->ax_rblen < AX_PDU_HEADER20 + header.aph_plength) { | |||
| 162 | errno(*__errno()) = EAGAIN35; | |||
| 163 | return NULL((void *)0); | |||
| 164 | } | |||
| 165 | } | |||
| 166 | ||||
| 167 | if ((pdu = calloc(1, sizeof(*pdu))) == NULL((void *)0)) | |||
| 168 | return NULL((void *)0); | |||
| 169 | ||||
| 170 | memcpy(&(pdu->ap_header), &header, sizeof(header)); | |||
| 171 | ||||
| 172 | #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE) | |||
| 173 | { | |||
| 174 | char chars[4]; | |||
| 175 | int print = 1; | |||
| 176 | ||||
| 177 | fprintf(stderr(&__sF[2]), "received packet:\n"); | |||
| 178 | for (i = 0; i < pdu->ap_header.aph_plength + AX_PDU_HEADER20; | |||
| 179 | i++) { | |||
| 180 | fprintf(stderr(&__sF[2]), "%02hhx ", ax->ax_rbuf[i]); | |||
| 181 | chars[i % 4] = ax->ax_rbuf[i]; | |||
| 182 | if (!isprint(ax->ax_rbuf[i])) | |||
| 183 | print = 0; | |||
| 184 | if (i % 4 == 3) { | |||
| 185 | if (print) | |||
| 186 | fprintf(stderr(&__sF[2]), "%.4s", chars); | |||
| 187 | fprintf(stderr(&__sF[2]), "\n"); | |||
| 188 | print = 1; | |||
| 189 | } | |||
| 190 | } | |||
| 191 | } | |||
| 192 | #endif | |||
| 193 | ||||
| 194 | u8 = (ax->ax_rbuf) + AX_PDU_HEADER20; | |||
| 195 | rawlen = pdu->ap_header.aph_plength; | |||
| 196 | if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT(1 << 3)) { | |||
| 197 | nread = ax_pdutoostring(&header, &(pdu->ap_context), u8, | |||
| 198 | rawlen); | |||
| 199 | if (nread == -1) | |||
| 200 | goto fail; | |||
| 201 | rawlen -= nread; | |||
| 202 | u8 += nread; | |||
| 203 | } | |||
| 204 | ||||
| 205 | switch (pdu->ap_header.aph_type) { | |||
| 206 | case AX_PDU_TYPE_GETBULK: | |||
| 207 | if (rawlen < 4) { | |||
| 208 | errno(*__errno()) = EPROTO95; | |||
| 209 | goto fail; | |||
| 210 | } | |||
| 211 | pdu->ap_payload.ap_getbulk.ap_nonrep = | |||
| 212 | ax_pdutoh16(&header, u8); | |||
| 213 | u8 += 2; | |||
| 214 | pdu->ap_payload.ap_getbulk.ap_maxrep = | |||
| 215 | ax_pdutoh16(&header, u8); | |||
| 216 | u8 += 2; | |||
| 217 | srl = &(pdu->ap_payload.ap_getbulk.ap_srl); | |||
| 218 | rawlen -= 4; | |||
| 219 | /* FALLTHROUGH */ | |||
| 220 | case AX_PDU_TYPE_GET: | |||
| 221 | case AX_PDU_TYPE_GETNEXT: | |||
| 222 | if (pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK) | |||
| 223 | srl = &(pdu->ap_payload.ap_srl); | |||
| 224 | while (rawlen > 0 ) { | |||
| 225 | srl->ap_nsr++; | |||
| 226 | sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr)); | |||
| 227 | if (sr == NULL((void *)0)) | |||
| 228 | goto fail; | |||
| 229 | srl->ap_sr = sr; | |||
| 230 | sr += (srl->ap_nsr - 1); | |||
| 231 | if ((nread = ax_pdutooid(&header, &(sr->asr_start), | |||
| 232 | u8, rawlen)) == -1) | |||
| 233 | goto fail; | |||
| 234 | rawlen -= nread; | |||
| 235 | u8 += nread; | |||
| 236 | if ((nread = ax_pdutooid(&header, &(sr->asr_stop), | |||
| 237 | u8, rawlen)) == -1) | |||
| 238 | goto fail; | |||
| 239 | rawlen -= nread; | |||
| 240 | u8 += nread; | |||
| 241 | } | |||
| 242 | break; | |||
| 243 | case AX_PDU_TYPE_TESTSET: | |||
| 244 | vbl = &(pdu->ap_payload.ap_vbl); | |||
| 245 | while (rawlen > 0) { | |||
| 246 | varbind = recallocarray(vbl->ap_varbind, | |||
| 247 | vbl->ap_nvarbind, vbl->ap_nvarbind + 1, | |||
| 248 | sizeof(*(vbl->ap_varbind))); | |||
| 249 | if (varbind == NULL((void *)0)) | |||
| 250 | goto fail; | |||
| 251 | vbl->ap_varbind = varbind; | |||
| 252 | nread = ax_pdutovarbind(&header, | |||
| 253 | &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen); | |||
| 254 | if (nread == -1) | |||
| 255 | goto fail; | |||
| 256 | vbl->ap_nvarbind++; | |||
| 257 | u8 += nread; | |||
| 258 | rawlen -= nread; | |||
| 259 | } | |||
| 260 | break; | |||
| 261 | case AX_PDU_TYPE_COMMITSET: | |||
| 262 | case AX_PDU_TYPE_UNDOSET: | |||
| 263 | case AX_PDU_TYPE_CLEANUPSET: | |||
| 264 | if (rawlen != 0) { | |||
| 265 | errno(*__errno()) = EPROTO95; | |||
| 266 | goto fail; | |||
| 267 | } | |||
| 268 | break; | |||
| 269 | case AX_PDU_TYPE_RESPONSE: | |||
| 270 | if (ax->ax_packetids != NULL((void *)0)) { | |||
| 271 | found = 0; | |||
| 272 | for (i = 0; ax->ax_packetids[i] != 0; i++) { | |||
| 273 | if (ax->ax_packetids[i] == | |||
| 274 | pdu->ap_header.aph_packetid) { | |||
| 275 | packetidx = i; | |||
| 276 | found = 1; | |||
| 277 | } | |||
| 278 | } | |||
| 279 | if (found) { | |||
| 280 | ax->ax_packetids[packetidx] = | |||
| 281 | ax->ax_packetids[i - 1]; | |||
| 282 | ax->ax_packetids[i - 1] = 0; | |||
| 283 | } else { | |||
| 284 | errno(*__errno()) = EPROTO95; | |||
| 285 | goto fail; | |||
| 286 | } | |||
| 287 | } | |||
| 288 | if (rawlen < 8) { | |||
| 289 | errno(*__errno()) = EPROTO95; | |||
| 290 | goto fail; | |||
| 291 | } | |||
| 292 | response = &(pdu->ap_payload.ap_response); | |||
| 293 | response->ap_uptime = ax_pdutoh32(&header, u8); | |||
| 294 | u8 += 4; | |||
| 295 | response->ap_error = ax_pdutoh16(&header, u8); | |||
| 296 | u8 += 2; | |||
| 297 | response->ap_index = ax_pdutoh16(&header, u8); | |||
| 298 | u8 += 2; | |||
| 299 | rawlen -= 8; | |||
| 300 | while (rawlen > 0) { | |||
| 301 | varbind = recallocarray(response->ap_varbindlist, | |||
| 302 | response->ap_nvarbind, response->ap_nvarbind + 1, | |||
| 303 | sizeof(*(response->ap_varbindlist))); | |||
| 304 | if (varbind == NULL((void *)0)) | |||
| 305 | goto fail; | |||
| 306 | response->ap_varbindlist = varbind; | |||
| 307 | nread = ax_pdutovarbind(&header, | |||
| 308 | &(response->ap_varbindlist[response->ap_nvarbind]), | |||
| 309 | u8, rawlen); | |||
| 310 | if (nread == -1) | |||
| 311 | goto fail; | |||
| 312 | response->ap_nvarbind++; | |||
| 313 | u8 += nread; | |||
| 314 | rawlen -= nread; | |||
| 315 | } | |||
| 316 | break; | |||
| 317 | default: | |||
| 318 | pdu->ap_payload.ap_raw = malloc(pdu->ap_header.aph_plength); | |||
| 319 | if (pdu->ap_payload.ap_raw == NULL((void *)0)) | |||
| 320 | goto fail; | |||
| 321 | memcpy(pdu->ap_payload.ap_raw, ax->ax_rbuf + AX_PDU_HEADER20, | |||
| 322 | pdu->ap_header.aph_plength); | |||
| 323 | break; | |||
| 324 | } | |||
| 325 | ||||
| 326 | ax->ax_rblen = 0; | |||
| 327 | ||||
| 328 | return pdu; | |||
| 329 | fail: | |||
| 330 | ax_pdu_free(pdu); | |||
| 331 | return NULL((void *)0); | |||
| 332 | } | |||
| 333 | ||||
| 334 | static int | |||
| 335 | ax_pdu_need(struct ax *ax, size_t need) | |||
| 336 | { | |||
| 337 | uint8_t *wbuf; | |||
| 338 | size_t wbsize; | |||
| 339 | ||||
| 340 | if (ax->ax_wbtlen + need >= ax->ax_wbsize) { | |||
| 341 | wbsize = (((ax->ax_wbtlen + need) / 512) + 1) * 512; | |||
| 342 | wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1); | |||
| 343 | if (wbuf == NULL((void *)0)) { | |||
| 344 | ax->ax_wbtlen = ax->ax_wblen; | |||
| 345 | return -1; | |||
| 346 | } | |||
| 347 | ax->ax_wbsize = wbsize; | |||
| 348 | ax->ax_wbuf = wbuf; | |||
| 349 | } | |||
| 350 | ||||
| 351 | return 0; | |||
| 352 | } | |||
| 353 | ||||
| 354 | ssize_t | |||
| 355 | ax_send(struct ax *ax) | |||
| 356 | { | |||
| 357 | ssize_t nwrite; | |||
| 358 | ||||
| 359 | if (ax->ax_wblen != ax->ax_wbtlen) { | |||
| 360 | errno(*__errno()) = EALREADY37; | |||
| 361 | return -1; | |||
| 362 | } | |||
| 363 | ||||
| 364 | if (ax->ax_wblen == 0) | |||
| 365 | return 0; | |||
| 366 | ||||
| 367 | #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE) | |||
| 368 | { | |||
| 369 | size_t i; | |||
| 370 | char chars[4]; | |||
| 371 | int print = 1; | |||
| 372 | ||||
| 373 | fprintf(stderr(&__sF[2]), "sending packet:\n"); | |||
| 374 | for (i = 0; i < ax->ax_wblen; i++) { | |||
| 375 | fprintf(stderr(&__sF[2]), "%02hhx ", ax->ax_wbuf[i]); | |||
| 376 | chars[i % 4] = ax->ax_wbuf[i]; | |||
| 377 | if (!isprint(ax->ax_wbuf[i])) | |||
| 378 | print = 0; | |||
| 379 | if (i % 4 == 3) { | |||
| 380 | if (print) | |||
| 381 | fprintf(stderr(&__sF[2]), "%.4s", chars); | |||
| 382 | fprintf(stderr(&__sF[2]), "\n"); | |||
| 383 | print = 1; | |||
| 384 | } | |||
| 385 | } | |||
| 386 | } | |||
| 387 | #endif | |||
| 388 | ||||
| 389 | if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen, | |||
| 390 | MSG_NOSIGNAL0x400 | MSG_DONTWAIT0x80)) == -1) | |||
| 391 | return -1; | |||
| 392 | ||||
| 393 | memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite); | |||
| 394 | ax->ax_wblen -= nwrite; | |||
| 395 | ax->ax_wbtlen = ax->ax_wblen; | |||
| 396 | ||||
| 397 | return ax->ax_wblen; | |||
| 398 | } | |||
| 399 | ||||
| 400 | uint32_t | |||
| 401 | ax_open(struct ax *ax, uint8_t timeout, struct ax_oid *oid, | |||
| 402 | struct ax_ostring *descr) | |||
| 403 | { | |||
| 404 | if (ax_pdu_header(ax, AX_PDU_TYPE_OPEN, 0, 0, 0, 0, | |||
| 405 | NULL((void *)0)) == -1) | |||
| 406 | return 0; | |||
| 407 | ax_pdu_need(ax, 4); | |||
| 408 | ax->ax_wbuf[ax->ax_wbtlen++] = timeout; | |||
| 409 | memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3); | |||
| 410 | ax->ax_wbtlen += 3; | |||
| 411 | if (ax_pdu_add_oid(ax, oid, 0) == -1) | |||
| 412 | return 0; | |||
| 413 | if (ax_pdu_add_str(ax, descr) == -1) | |||
| 414 | return 0; | |||
| 415 | ||||
| 416 | return ax_pdu_queue(ax); | |||
| 417 | } | |||
| 418 | ||||
| 419 | uint32_t | |||
| 420 | ax_close(struct ax *ax, uint32_t sessionid, | |||
| 421 | enum ax_close_reason reason) | |||
| 422 | { | |||
| 423 | if (ax_pdu_header(ax, AX_PDU_TYPE_CLOSE, 0, sessionid, 0, 0, | |||
| 424 | NULL((void *)0)) == -1) | |||
| 425 | return 0; | |||
| 426 | ||||
| 427 | if (ax_pdu_need(ax, 4) == -1) | |||
| 428 | return 0; | |||
| 429 | ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason; | |||
| 430 | memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3); | |||
| 431 | ax->ax_wbtlen += 3; | |||
| 432 | ||||
| 433 | return ax_pdu_queue(ax); | |||
| 434 | } | |||
| 435 | ||||
| 436 | uint32_t | |||
| 437 | ax_indexallocate(struct ax *ax, uint8_t flags, uint32_t sessionid, | |||
| 438 | struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb) | |||
| 439 | { | |||
| 440 | if (flags & ~(AX_PDU_FLAG_NEW_INDEX(1 << 1) | AX_PDU_FLAG_ANY_INDEX(1 << 2))) { | |||
| 441 | errno(*__errno()) = EINVAL22; | |||
| 442 | return 0; | |||
| 443 | } | |||
| 444 | ||||
| 445 | if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXALLOCATE, flags, | |||
| 446 | sessionid, 0, 0, context) == -1) | |||
| 447 | return 0; | |||
| 448 | ||||
| 449 | if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) | |||
| 450 | return 0; | |||
| 451 | ||||
| 452 | return ax_pdu_queue(ax); | |||
| 453 | } | |||
| 454 | ||||
| 455 | uint32_t | |||
| 456 | ax_indexdeallocate(struct ax *ax, uint32_t sessionid, | |||
| 457 | struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb) | |||
| 458 | { | |||
| 459 | if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXDEALLOCATE, 0, | |||
| 460 | sessionid, 0, 0, context) == -1) | |||
| 461 | return 0; | |||
| 462 | ||||
| 463 | if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) | |||
| 464 | return 0; | |||
| 465 | ||||
| 466 | return ax_pdu_queue(ax); | |||
| 467 | } | |||
| 468 | ||||
| 469 | uint32_t | |||
| 470 | ax_addagentcaps(struct ax *ax, uint32_t sessionid, | |||
| 471 | struct ax_ostring *context, struct ax_oid *id, | |||
| 472 | struct ax_ostring *descr) | |||
| 473 | { | |||
| 474 | if (ax_pdu_header(ax, AX_PDU_TYPE_ADDAGENTCAPS, 0, | |||
| 475 | sessionid, 0, 0, context) == -1) | |||
| 476 | return 0; | |||
| 477 | if (ax_pdu_add_oid(ax, id, 0) == -1) | |||
| 478 | return 0; | |||
| 479 | if (ax_pdu_add_str(ax, descr) == -1) | |||
| 480 | return 0; | |||
| 481 | ||||
| 482 | return ax_pdu_queue(ax); | |||
| 483 | } | |||
| 484 | ||||
| 485 | uint32_t | |||
| 486 | ax_removeagentcaps(struct ax *ax, uint32_t sessionid, | |||
| 487 | struct ax_ostring *context, struct ax_oid *id) | |||
| 488 | { | |||
| 489 | if (ax_pdu_header(ax, AX_PDU_TYPE_REMOVEAGENTCAPS, 0, | |||
| 490 | sessionid, 0, 0, context) == -1) | |||
| 491 | return 0; | |||
| 492 | if (ax_pdu_add_oid(ax, id, 0) == -1) | |||
| 493 | return 0; | |||
| 494 | ||||
| 495 | return ax_pdu_queue(ax); | |||
| 496 | ||||
| 497 | } | |||
| 498 | ||||
| 499 | uint32_t | |||
| 500 | ax_register(struct ax *ax, uint8_t flags, uint32_t sessionid, | |||
| 501 | struct ax_ostring *context, uint8_t timeout, uint8_t priority, | |||
| 502 | uint8_t range_subid, struct ax_oid *subtree, uint32_t upperbound) | |||
| 503 | { | |||
| 504 | if (flags & ~(AX_PDU_FLAG_INSTANCE_REGISTRATION(1 << 0))) { | |||
| 505 | errno(*__errno()) = EINVAL22; | |||
| 506 | return 0; | |||
| 507 | } | |||
| 508 | ||||
| 509 | if (ax_pdu_header(ax, AX_PDU_TYPE_REGISTER, flags, | |||
| 510 | sessionid, 0, 0, context) == -1) | |||
| 511 | return 0; | |||
| 512 | ||||
| 513 | if (ax_pdu_need(ax, 4) == -1) | |||
| 514 | return 0; | |||
| 515 | ax->ax_wbuf[ax->ax_wbtlen++] = timeout; | |||
| 516 | ax->ax_wbuf[ax->ax_wbtlen++] = priority; | |||
| 517 | ax->ax_wbuf[ax->ax_wbtlen++] = range_subid; | |||
| 518 | ax->ax_wbuf[ax->ax_wbtlen++] = 0; | |||
| 519 | if (ax_pdu_add_oid(ax, subtree, 0) == -1) | |||
| 520 | return 0; | |||
| 521 | if (range_subid != 0) { | |||
| 522 | if (ax_pdu_add_uint32(ax, upperbound) == -1) | |||
| 523 | return 0; | |||
| 524 | } | |||
| 525 | ||||
| 526 | return ax_pdu_queue(ax); | |||
| 527 | } | |||
| 528 | ||||
| 529 | uint32_t | |||
| 530 | ax_unregister(struct ax *ax, uint32_t sessionid, | |||
| 531 | struct ax_ostring *context, uint8_t priority, uint8_t range_subid, | |||
| 532 | struct ax_oid *subtree, uint32_t upperbound) | |||
| 533 | { | |||
| 534 | if (ax_pdu_header(ax, AX_PDU_TYPE_UNREGISTER, 0, | |||
| 535 | sessionid, 0, 0, context) == -1) | |||
| 536 | return 0; | |||
| 537 | ||||
| 538 | if (ax_pdu_need(ax, 4) == -1) | |||
| 539 | return 0; | |||
| 540 | ax->ax_wbuf[ax->ax_wbtlen++] = 0; | |||
| 541 | ax->ax_wbuf[ax->ax_wbtlen++] = priority; | |||
| 542 | ax->ax_wbuf[ax->ax_wbtlen++] = range_subid; | |||
| 543 | ax->ax_wbuf[ax->ax_wbtlen++] = 0; | |||
| 544 | if (ax_pdu_add_oid(ax, subtree, 0) == -1) | |||
| 545 | return 0; | |||
| 546 | if (range_subid != 0) { | |||
| 547 | if (ax_pdu_add_uint32(ax, upperbound) == -1) | |||
| 548 | return 0; | |||
| 549 | } | |||
| 550 | ||||
| 551 | return ax_pdu_queue(ax); | |||
| 552 | } | |||
| 553 | ||||
| 554 | int | |||
| 555 | ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid, | |||
| 556 | uint32_t packetid, struct ax_ostring *context, uint32_t sysuptime, | |||
| 557 | uint16_t error, uint16_t index, struct ax_varbind *vblist, size_t nvb) | |||
| 558 | { | |||
| 559 | if (ax_pdu_header(ax, AX_PDU_TYPE_RESPONSE, 0, sessionid, | |||
| ||||
| 560 | transactionid, packetid, context) == -1) | |||
| 561 | return -1; | |||
| 562 | ||||
| 563 | if (ax_pdu_add_uint32(ax, sysuptime) == -1 || | |||
| 564 | ax_pdu_add_uint16(ax, error) == -1 || | |||
| 565 | ax_pdu_add_uint16(ax, index) == -1) | |||
| 566 | return -1; | |||
| 567 | ||||
| 568 | if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) | |||
| 569 | return -1; | |||
| 570 | if (ax_pdu_queue(ax) == 0) | |||
| 571 | return -1; | |||
| 572 | return 0; | |||
| 573 | } | |||
| 574 | ||||
| 575 | void | |||
| 576 | ax_pdu_free(struct ax_pdu *pdu) | |||
| 577 | { | |||
| 578 | size_t i; | |||
| 579 | struct ax_pdu_response *response; | |||
| 580 | ||||
| 581 | if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT(1 << 3)) | |||
| 582 | free(pdu->ap_context.aos_string); | |||
| 583 | ||||
| 584 | switch (pdu->ap_header.aph_type) { | |||
| 585 | case AX_PDU_TYPE_GET: | |||
| 586 | case AX_PDU_TYPE_GETNEXT: | |||
| 587 | case AX_PDU_TYPE_GETBULK: | |||
| 588 | free(pdu->ap_payload.ap_srl.ap_sr); | |||
| 589 | break; | |||
| 590 | case AX_PDU_TYPE_RESPONSE: | |||
| 591 | response = &(pdu->ap_payload.ap_response); | |||
| 592 | for (i = 0; i < response->ap_nvarbind; i++) | |||
| 593 | ax_varbind_free(&(response->ap_varbindlist[i])); | |||
| 594 | free(response->ap_varbindlist); | |||
| 595 | break; | |||
| 596 | default: | |||
| 597 | free(pdu->ap_payload.ap_raw); | |||
| 598 | break; | |||
| 599 | } | |||
| 600 | free(pdu); | |||
| 601 | } | |||
| 602 | ||||
| 603 | void | |||
| 604 | ax_varbind_free(struct ax_varbind *varbind) | |||
| 605 | { | |||
| 606 | switch (varbind->avb_type) { | |||
| 607 | case AX_DATA_TYPE_OCTETSTRING: | |||
| 608 | case AX_DATA_TYPE_IPADDRESS: | |||
| 609 | case AX_DATA_TYPE_OPAQUE: | |||
| 610 | free(varbind->avb_data.avb_ostring.aos_string); | |||
| 611 | break; | |||
| 612 | default: | |||
| 613 | break; | |||
| 614 | } | |||
| 615 | } | |||
| 616 | ||||
| 617 | const char * | |||
| 618 | ax_error2string(enum ax_pdu_error error) | |||
| 619 | { | |||
| 620 | static char buffer[64]; | |||
| 621 | switch (error) { | |||
| 622 | case AX_PDU_ERROR_NOERROR: | |||
| 623 | return "No error"; | |||
| 624 | case AX_PDU_ERROR_GENERR: | |||
| 625 | return "Generic error"; | |||
| 626 | case AX_PDU_ERROR_NOACCESS: | |||
| 627 | return "No access"; | |||
| 628 | case AX_PDU_ERROR_WRONGTYPE: | |||
| 629 | return "Wrong type"; | |||
| 630 | case AX_PDU_ERROR_WRONGLENGTH: | |||
| 631 | return "Wrong length"; | |||
| 632 | case AX_PDU_ERROR_WRONGENCODING: | |||
| 633 | return "Wrong encoding"; | |||
| 634 | case AX_PDU_ERROR_WRONGVALUE: | |||
| 635 | return "Wrong value"; | |||
| 636 | case AX_PDU_ERROR_NOCREATION: | |||
| 637 | return "No creation"; | |||
| 638 | case AX_PDU_ERROR_INCONSISTENTVALUE: | |||
| 639 | return "Inconsistent value"; | |||
| 640 | case AX_PDU_ERROR_RESOURCEUNAVAILABLE: | |||
| 641 | return "Resource unavailable"; | |||
| 642 | case AX_PDU_ERROR_COMMITFAILED: | |||
| 643 | return "Commit failed"; | |||
| 644 | case AX_PDU_ERROR_UNDOFAILED: | |||
| 645 | return "Undo failed"; | |||
| 646 | case AX_PDU_ERROR_NOTWRITABLE: | |||
| 647 | return "Not writable"; | |||
| 648 | case AX_PDU_ERROR_INCONSISTENTNAME: | |||
| 649 | return "Inconsistent name"; | |||
| 650 | case AX_PDU_ERROR_OPENFAILED: | |||
| 651 | return "Open Failed"; | |||
| 652 | case AX_PDU_ERROR_NOTOPEN: | |||
| 653 | return "Not open"; | |||
| 654 | case AX_PDU_ERROR_INDEXWRONGTYPE: | |||
| 655 | return "Index wrong type"; | |||
| 656 | case AX_PDU_ERROR_INDEXALREADYALLOCATED: | |||
| 657 | return "Index already allocated"; | |||
| 658 | case AX_PDU_ERROR_INDEXNONEAVAILABLE: | |||
| 659 | return "Index none available"; | |||
| 660 | case AX_PDU_ERROR_INDEXNOTALLOCATED: | |||
| 661 | return "Index not allocated"; | |||
| 662 | case AX_PDU_ERROR_UNSUPPORTEDCONETXT: | |||
| 663 | return "Unsupported context"; | |||
| 664 | case AX_PDU_ERROR_DUPLICATEREGISTRATION: | |||
| 665 | return "Duplicate registration"; | |||
| 666 | case AX_PDU_ERROR_UNKNOWNREGISTRATION: | |||
| 667 | return "Unkown registration"; | |||
| 668 | case AX_PDU_ERROR_UNKNOWNAGENTCAPS: | |||
| 669 | return "Unknown agent capabilities"; | |||
| 670 | case AX_PDU_ERROR_PARSEERROR: | |||
| 671 | return "Parse error"; | |||
| 672 | case AX_PDU_ERROR_REQUESTDENIED: | |||
| 673 | return "Request denied"; | |||
| 674 | case AX_PDU_ERROR_PROCESSINGERROR: | |||
| 675 | return "Processing error"; | |||
| 676 | } | |||
| 677 | snprintf(buffer, sizeof(buffer), "Unknown error: %d", error); | |||
| 678 | return buffer; | |||
| 679 | } | |||
| 680 | ||||
| 681 | const char * | |||
| 682 | ax_pdutype2string(enum ax_pdu_type type) | |||
| 683 | { | |||
| 684 | static char buffer[64]; | |||
| 685 | switch(type) { | |||
| 686 | case AX_PDU_TYPE_OPEN: | |||
| 687 | return "agentx-Open-PDU"; | |||
| 688 | case AX_PDU_TYPE_CLOSE: | |||
| 689 | return "agentx-Close-PDU"; | |||
| 690 | case AX_PDU_TYPE_REGISTER: | |||
| 691 | return "agentx-Register-PDU"; | |||
| 692 | case AX_PDU_TYPE_UNREGISTER: | |||
| 693 | return "agentx-Unregister-PDU"; | |||
| 694 | case AX_PDU_TYPE_GET: | |||
| 695 | return "agentx-Get-PDU"; | |||
| 696 | case AX_PDU_TYPE_GETNEXT: | |||
| 697 | return "agentx-GetNext-PDU"; | |||
| 698 | case AX_PDU_TYPE_GETBULK: | |||
| 699 | return "agentx-GetBulk-PDU"; | |||
| 700 | case AX_PDU_TYPE_TESTSET: | |||
| 701 | return "agentx-TestSet-PDU"; | |||
| 702 | case AX_PDU_TYPE_COMMITSET: | |||
| 703 | return "agentx-CommitSet-PDU"; | |||
| 704 | case AX_PDU_TYPE_UNDOSET: | |||
| 705 | return "agentx-UndoSet-PDU"; | |||
| 706 | case AX_PDU_TYPE_CLEANUPSET: | |||
| 707 | return "agentx-CleanupSet-PDU"; | |||
| 708 | case AX_PDU_TYPE_NOTIFY: | |||
| 709 | return "agentx-Notify-PDU"; | |||
| 710 | case AX_PDU_TYPE_PING: | |||
| 711 | return "agentx-Ping-PDU"; | |||
| 712 | case AX_PDU_TYPE_INDEXALLOCATE: | |||
| 713 | return "agentx-IndexAllocate-PDU"; | |||
| 714 | case AX_PDU_TYPE_INDEXDEALLOCATE: | |||
| 715 | return "agentx-IndexDeallocate-PDU"; | |||
| 716 | case AX_PDU_TYPE_ADDAGENTCAPS: | |||
| 717 | return "agentx-AddAgentCaps-PDU"; | |||
| 718 | case AX_PDU_TYPE_REMOVEAGENTCAPS: | |||
| 719 | return "agentx-RemoveAgentCaps-PDU"; | |||
| 720 | case AX_PDU_TYPE_RESPONSE: | |||
| 721 | return "agentx-Response-PDU"; | |||
| 722 | } | |||
| 723 | snprintf(buffer, sizeof(buffer), "Unknown type: %d", type); | |||
| 724 | return buffer; | |||
| 725 | } | |||
| 726 | ||||
| 727 | const char * | |||
| 728 | ax_closereason2string(enum ax_close_reason reason) | |||
| 729 | { | |||
| 730 | static char buffer[64]; | |||
| 731 | ||||
| 732 | switch (reason) { | |||
| 733 | case AX_CLOSE_OTHER: | |||
| 734 | return "Undefined reason"; | |||
| 735 | case AX_CLOSEN_PARSEERROR: | |||
| 736 | return "Too many AgentX parse errors from peer"; | |||
| 737 | case AX_CLOSE_PROTOCOLERROR: | |||
| 738 | return "Too many AgentX protocol errors from peer"; | |||
| 739 | case AX_CLOSE_TIMEOUTS: | |||
| 740 | return "Too many timeouts waiting for peer"; | |||
| 741 | case AX_CLOSE_SHUTDOWN: | |||
| 742 | return "shutting down"; | |||
| 743 | case AX_CLOSE_BYMANAGER: | |||
| 744 | return "Manager shuts down"; | |||
| 745 | } | |||
| 746 | snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason); | |||
| 747 | return buffer; | |||
| 748 | } | |||
| 749 | ||||
| 750 | const char * | |||
| 751 | ax_oid2string(struct ax_oid *oid) | |||
| 752 | { | |||
| 753 | return ax_oidrange2string(oid, 0, 0); | |||
| 754 | } | |||
| 755 | ||||
| 756 | const char * | |||
| 757 | ax_oidrange2string(struct ax_oid *oid, uint8_t range_subid, | |||
| 758 | uint32_t upperbound) | |||
| 759 | { | |||
| 760 | static char buf[1024]; | |||
| 761 | char *p; | |||
| 762 | size_t i, rest; | |||
| 763 | int ret; | |||
| 764 | ||||
| 765 | rest = sizeof(buf); | |||
| 766 | p = buf; | |||
| 767 | if (oid->aoi_idlen == 0) | |||
| 768 | (void)strlcpy(buf, "null", sizeof(buf)); | |||
| 769 | for (i = 0; i < oid->aoi_idlen; i++) { | |||
| 770 | if (range_subid != 0 && range_subid - 1 == (uint8_t)i) | |||
| 771 | ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i], | |||
| 772 | upperbound); | |||
| 773 | else | |||
| 774 | ret = snprintf(p, rest, ".%u", oid->aoi_id[i]); | |||
| 775 | if ((size_t) ret >= rest) { | |||
| 776 | snprintf(buf, sizeof(buf), "Couldn't parse oid"); | |||
| 777 | return buf; | |||
| 778 | } | |||
| 779 | p += ret; | |||
| 780 | rest -= (size_t) ret; | |||
| 781 | } | |||
| 782 | return buf; | |||
| 783 | } | |||
| 784 | ||||
| 785 | const char * | |||
| 786 | ax_varbind2string(struct ax_varbind *vb) | |||
| 787 | { | |||
| 788 | static char buf[1024]; | |||
| 789 | char tmpbuf[1024]; | |||
| 790 | size_t i, bufleft; | |||
| 791 | int ishex = 0; | |||
| 792 | char *p; | |||
| 793 | int ret; | |||
| 794 | ||||
| 795 | switch (vb->avb_type) { | |||
| 796 | case AX_DATA_TYPE_INTEGER: | |||
| 797 | snprintf(buf, sizeof(buf), "%s: (int)%d", | |||
| 798 | ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_int32); | |||
| 799 | break; | |||
| 800 | case AX_DATA_TYPE_OCTETSTRING: | |||
| 801 | for (i = 0; | |||
| 802 | i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) { | |||
| 803 | if (!isprint(vb->avb_data.avb_ostring.aos_string[i])) | |||
| 804 | ishex = 1; | |||
| 805 | } | |||
| 806 | if (ishex) { | |||
| 807 | p = tmpbuf; | |||
| 808 | bufleft = sizeof(tmpbuf); | |||
| 809 | for (i = 0; | |||
| 810 | i < vb->avb_data.avb_ostring.aos_slen; i++) { | |||
| 811 | ret = snprintf(p, bufleft, " %02hhX", | |||
| 812 | vb->avb_data.avb_ostring.aos_string[i]); | |||
| 813 | if (ret >= (int) bufleft) { | |||
| 814 | p = strrchr(p, ' '); | |||
| 815 | strlcpy(p, "...", 4); | |||
| 816 | break; | |||
| 817 | } | |||
| 818 | p += 3; | |||
| 819 | bufleft -= 3; | |||
| 820 | } | |||
| 821 | ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s", | |||
| 822 | ax_oid2string(&(vb->avb_oid)), tmpbuf); | |||
| 823 | if (ret >= (int) sizeof(buf)) { | |||
| 824 | p = strrchr(buf, ' '); | |||
| 825 | strlcpy(p, "...", 4); | |||
| 826 | } | |||
| 827 | } else { | |||
| 828 | ret = snprintf(buf, sizeof(buf), "%s: (string)", | |||
| 829 | ax_oid2string(&(vb->avb_oid))); | |||
| 830 | if (ret >= (int) sizeof(buf)) { | |||
| 831 | snprintf(buf, sizeof(buf), "<too large OID>: " | |||
| 832 | "(string)<too large string>"); | |||
| 833 | break; | |||
| 834 | } | |||
| 835 | p = buf + ret; | |||
| 836 | bufleft = (int) sizeof(buf) - ret; | |||
| 837 | if (snprintf(p, bufleft, "%.*s", | |||
| 838 | vb->avb_data.avb_ostring.aos_slen, | |||
| 839 | vb->avb_data.avb_ostring.aos_string) >= | |||
| 840 | (int) bufleft) { | |||
| 841 | p = buf + sizeof(buf) - 4; | |||
| 842 | strlcpy(p, "...", 4); | |||
| 843 | } | |||
| 844 | } | |||
| 845 | break; | |||
| 846 | case AX_DATA_TYPE_NULL: | |||
| 847 | snprintf(buf, sizeof(buf), "%s: <null>", | |||
| 848 | ax_oid2string(&(vb->avb_oid))); | |||
| 849 | break; | |||
| 850 | case AX_DATA_TYPE_OID: | |||
| 851 | strlcpy(tmpbuf, | |||
| 852 | ax_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf)); | |||
| 853 | snprintf(buf, sizeof(buf), "%s: (oid)%s", | |||
| 854 | ax_oid2string(&(vb->avb_oid)), tmpbuf); | |||
| 855 | break; | |||
| 856 | case AX_DATA_TYPE_IPADDRESS: | |||
| 857 | if (vb->avb_data.avb_ostring.aos_slen != 4) { | |||
| 858 | snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>", | |||
| 859 | ax_oid2string(&(vb->avb_oid))); | |||
| 860 | break; | |||
| 861 | } | |||
| 862 | if (inet_ntop(PF_INET2, vb->avb_data.avb_ostring.aos_string, | |||
| 863 | tmpbuf, sizeof(tmpbuf)) == NULL((void *)0)) { | |||
| 864 | snprintf(buf, sizeof(buf), "%s: (ipaddress)" | |||
| 865 | "<unparseable>: %s", | |||
| 866 | ax_oid2string(&(vb->avb_oid)), | |||
| 867 | strerror(errno(*__errno()))); | |||
| 868 | break; | |||
| 869 | } | |||
| 870 | snprintf(buf, sizeof(buf), "%s: (ipaddress)%s", | |||
| 871 | ax_oid2string(&(vb->avb_oid)), tmpbuf); | |||
| 872 | break; | |||
| 873 | case AX_DATA_TYPE_COUNTER32: | |||
| 874 | snprintf(buf, sizeof(buf), "%s: (counter32)%u", | |||
| 875 | ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); | |||
| 876 | break; | |||
| 877 | case AX_DATA_TYPE_GAUGE32: | |||
| 878 | snprintf(buf, sizeof(buf), "%s: (gauge32)%u", | |||
| 879 | ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); | |||
| 880 | break; | |||
| 881 | case AX_DATA_TYPE_TIMETICKS: | |||
| 882 | snprintf(buf, sizeof(buf), "%s: (timeticks)%u", | |||
| 883 | ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); | |||
| 884 | break; | |||
| 885 | case AX_DATA_TYPE_OPAQUE: | |||
| 886 | p = tmpbuf; | |||
| 887 | bufleft = sizeof(tmpbuf); | |||
| 888 | for (i = 0; | |||
| 889 | i < vb->avb_data.avb_ostring.aos_slen; i++) { | |||
| 890 | ret = snprintf(p, bufleft, " %02hhX", | |||
| 891 | vb->avb_data.avb_ostring.aos_string[i]); | |||
| 892 | if (ret >= (int) bufleft) { | |||
| 893 | p = strrchr(p, ' '); | |||
| 894 | strlcpy(p, "...", 4); | |||
| 895 | break; | |||
| 896 | } | |||
| 897 | p += 3; | |||
| 898 | bufleft -= 3; | |||
| 899 | } | |||
| 900 | ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s", | |||
| 901 | ax_oid2string(&(vb->avb_oid)), tmpbuf); | |||
| 902 | if (ret >= (int) sizeof(buf)) { | |||
| 903 | p = strrchr(buf, ' '); | |||
| 904 | strlcpy(p, "...", 4); | |||
| 905 | } | |||
| 906 | break; | |||
| 907 | case AX_DATA_TYPE_COUNTER64: | |||
| 908 | snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64"llu", | |||
| 909 | ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64); | |||
| 910 | break; | |||
| 911 | case AX_DATA_TYPE_NOSUCHOBJECT: | |||
| 912 | snprintf(buf, sizeof(buf), "%s: <noSuchObject>", | |||
| 913 | ax_oid2string(&(vb->avb_oid))); | |||
| 914 | break; | |||
| 915 | case AX_DATA_TYPE_NOSUCHINSTANCE: | |||
| 916 | snprintf(buf, sizeof(buf), "%s: <noSuchInstance>", | |||
| 917 | ax_oid2string(&(vb->avb_oid))); | |||
| 918 | break; | |||
| 919 | case AX_DATA_TYPE_ENDOFMIBVIEW: | |||
| 920 | snprintf(buf, sizeof(buf), "%s: <endOfMibView>", | |||
| 921 | ax_oid2string(&(vb->avb_oid))); | |||
| 922 | break; | |||
| 923 | } | |||
| 924 | return buf; | |||
| 925 | } | |||
| 926 | ||||
| 927 | int | |||
| 928 | ax_oid_cmp(struct ax_oid *o1, struct ax_oid *o2) | |||
| 929 | { | |||
| 930 | size_t i, min; | |||
| 931 | ||||
| 932 | min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen; | |||
| 933 | for (i = 0; i < min; i++) { | |||
| 934 | if (o1->aoi_id[i] < o2->aoi_id[i]) | |||
| 935 | return -1; | |||
| 936 | if (o1->aoi_id[i] > o2->aoi_id[i]) | |||
| 937 | return 1; | |||
| 938 | } | |||
| 939 | /* o1 is parent of o2 */ | |||
| 940 | if (o1->aoi_idlen < o2->aoi_idlen) | |||
| 941 | return -2; | |||
| 942 | /* o1 is child of o2 */ | |||
| 943 | if (o1->aoi_idlen > o2->aoi_idlen) | |||
| 944 | return 2; | |||
| 945 | return 0; | |||
| 946 | } | |||
| 947 | ||||
| 948 | int | |||
| 949 | ax_oid_add(struct ax_oid *oid, uint32_t value) | |||
| 950 | { | |||
| 951 | if (oid->aoi_idlen == AX_OID_MAX_LEN128) | |||
| 952 | return -1; | |||
| 953 | oid->aoi_id[oid->aoi_idlen++] = value; | |||
| 954 | return 0; | |||
| 955 | } | |||
| 956 | ||||
| 957 | static uint32_t | |||
| 958 | ax_pdu_queue(struct ax *ax) | |||
| 959 | { | |||
| 960 | struct ax_pdu_header header; | |||
| 961 | uint32_t packetid, plength; | |||
| 962 | size_t wbtlen = ax->ax_wbtlen; | |||
| 963 | ||||
| 964 | header.aph_flags = ax->ax_byteorder == AX_BYTE_ORDER_BE ? | |||
| 965 | AX_PDU_FLAG_NETWORK_BYTE_ORDER(1 << 4) : 0; | |||
| 966 | packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12])); | |||
| 967 | plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER20; | |||
| 968 | ax->ax_wbtlen = ax->ax_wblen + 16; | |||
| 969 | (void)ax_pdu_add_uint32(ax, plength); | |||
| 970 | ||||
| 971 | ax->ax_wblen = ax->ax_wbtlen = wbtlen; | |||
| 972 | ||||
| 973 | return packetid; | |||
| 974 | } | |||
| 975 | ||||
| 976 | static int | |||
| 977 | ax_pdu_header(struct ax *ax, enum ax_pdu_type type, uint8_t flags, | |||
| 978 | uint32_t sessionid, uint32_t transactionid, uint32_t packetid, | |||
| 979 | struct ax_ostring *context) | |||
| 980 | { | |||
| 981 | if (ax->ax_wblen != ax->ax_wbtlen) { | |||
| 982 | errno(*__errno()) = EALREADY37; | |||
| 983 | return -1; | |||
| 984 | } | |||
| 985 | ||||
| 986 | if (ax_pdu_need(ax, 4) == -1) | |||
| 987 | return -1; | |||
| 988 | ax->ax_wbuf[ax->ax_wbtlen++] = 1; | |||
| 989 | ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type; | |||
| 990 | if (context != NULL((void *)0)) | |||
| 991 | flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT(1 << 3); | |||
| 992 | if (ax->ax_byteorder == AX_BYTE_ORDER_BE) | |||
| 993 | flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER(1 << 4); | |||
| 994 | ax->ax_wbuf[ax->ax_wbtlen++] = flags; | |||
| 995 | ax->ax_wbuf[ax->ax_wbtlen++] = 0; | |||
| 996 | if (packetid == 0) | |||
| 997 | packetid = ax_packetid(ax); | |||
| 998 | if (ax_pdu_add_uint32(ax, sessionid) == -1 || | |||
| 999 | ax_pdu_add_uint32(ax, transactionid) == -1 || | |||
| 1000 | ax_pdu_add_uint32(ax, packetid) == -1 || | |||
| 1001 | ax_pdu_need(ax, 4) == -1) | |||
| 1002 | return -1; | |||
| 1003 | ax->ax_wbtlen += 4; | |||
| 1004 | if (context != NULL((void *)0)) { | |||
| 1005 | if (ax_pdu_add_str(ax, context) == -1) | |||
| 1006 | return -1; | |||
| 1007 | } | |||
| 1008 | ||||
| 1009 | return 0; | |||
| 1010 | } | |||
| 1011 | ||||
| 1012 | static uint32_t | |||
| 1013 | ax_packetid(struct ax *ax) | |||
| 1014 | { | |||
| 1015 | uint32_t packetid, *packetids; | |||
| 1016 | size_t npackets = 0, i; | |||
| 1017 | int found; | |||
| 1018 | ||||
| 1019 | if (ax->ax_packetids != NULL((void *)0)) { | |||
| 1020 | for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++) | |||
| 1021 | continue; | |||
| 1022 | } | |||
| 1023 | if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) { | |||
| 1024 | packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize, | |||
| 1025 | ax->ax_packetidsize + 25, sizeof(*packetids)); | |||
| 1026 | if (packetids == NULL((void *)0)) | |||
| 1027 | return 0; | |||
| 1028 | ax->ax_packetidsize += 25; | |||
| 1029 | ax->ax_packetids = packetids; | |||
| 1030 | } | |||
| 1031 | do { | |||
| 1032 | found = 0; | |||
| 1033 | packetid = arc4random(); | |||
| 1034 | for (i = 0; ax->ax_packetids[i] != 0; i++) { | |||
| ||||
| 1035 | if (ax->ax_packetids[i] == packetid) { | |||
| 1036 | found = 1; | |||
| 1037 | break; | |||
| 1038 | } | |||
| 1039 | } | |||
| 1040 | } while (packetid == 0 || found); | |||
| 1041 | ax->ax_packetids[npackets] = packetid; | |||
| 1042 | ||||
| 1043 | return packetid; | |||
| 1044 | } | |||
| 1045 | ||||
| 1046 | static int | |||
| 1047 | ax_pdu_add_uint16(struct ax *ax, uint16_t value) | |||
| 1048 | { | |||
| 1049 | if (ax_pdu_need(ax, sizeof(value)) == -1) | |||
| 1050 | return -1; | |||
| 1051 | ||||
| 1052 | if (ax->ax_byteorder == AX_BYTE_ORDER_BE) | |||
| 1053 | value = htobe16(value)(__uint16_t)(__builtin_constant_p(value) ? (__uint16_t)(((__uint16_t )(value) & 0xffU) << 8 | ((__uint16_t)(value) & 0xff00U) >> 8) : __swap16md(value)); | |||
| 1054 | else | |||
| 1055 | value = htole16(value)((__uint16_t)(value)); | |||
| 1056 | memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); | |||
| 1057 | ax->ax_wbtlen += sizeof(value); | |||
| 1058 | return 0; | |||
| 1059 | } | |||
| 1060 | ||||
| 1061 | static int | |||
| 1062 | ax_pdu_add_uint32(struct ax *ax, uint32_t value) | |||
| 1063 | { | |||
| 1064 | if (ax_pdu_need(ax, sizeof(value)) == -1) | |||
| 1065 | return -1; | |||
| 1066 | ||||
| 1067 | if (ax->ax_byteorder == AX_BYTE_ORDER_BE) | |||
| 1068 | value = htobe32(value)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t )(value) & 0xff) << 24 | ((__uint32_t)(value) & 0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >> 8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md (value)); | |||
| 1069 | else | |||
| 1070 | value = htole32(value)((__uint32_t)(value)); | |||
| 1071 | memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); | |||
| 1072 | ax->ax_wbtlen += sizeof(value); | |||
| 1073 | return 0; | |||
| 1074 | } | |||
| 1075 | ||||
| 1076 | static int | |||
| 1077 | ax_pdu_add_uint64(struct ax *ax, uint64_t value) | |||
| 1078 | { | |||
| 1079 | if (ax_pdu_need(ax, sizeof(value)) == -1) | |||
| 1080 | return -1; | |||
| 1081 | ||||
| 1082 | if (ax->ax_byteorder == AX_BYTE_ORDER_BE) | |||
| 1083 | value = htobe64(value)(__uint64_t)(__builtin_constant_p(value) ? (__uint64_t)((((__uint64_t )(value) & 0xff) << 56) | ((__uint64_t)(value) & 0xff00ULL) << 40 | ((__uint64_t)(value) & 0xff0000ULL ) << 24 | ((__uint64_t)(value) & 0xff000000ULL) << 8 | ((__uint64_t)(value) & 0xff00000000ULL) >> 8 | ((__uint64_t)(value) & 0xff0000000000ULL) >> 24 | ( (__uint64_t)(value) & 0xff000000000000ULL) >> 40 | ( (__uint64_t)(value) & 0xff00000000000000ULL) >> 56) : __swap64md(value)); | |||
| 1084 | else | |||
| 1085 | value = htole64(value)((__uint64_t)(value)); | |||
| 1086 | memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); | |||
| 1087 | ax->ax_wbtlen += sizeof(value); | |||
| 1088 | return 0; | |||
| 1089 | } | |||
| 1090 | ||||
| 1091 | ||||
| 1092 | static int | |||
| 1093 | ax_pdu_add_oid(struct ax *ax, struct ax_oid *oid, int include) | |||
| 1094 | { | |||
| 1095 | static struct ax_oid nulloid = {0}; | |||
| 1096 | uint8_t prefix = 0, n_subid, i = 0; | |||
| 1097 | ||||
| 1098 | n_subid = oid->aoi_idlen; | |||
| 1099 | ||||
| 1100 | if (oid == NULL((void *)0)) | |||
| 1101 | oid = &nulloid; | |||
| 1102 | ||||
| 1103 | if (oid->aoi_idlen > 4 && | |||
| 1104 | oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 && | |||
| 1105 | oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 && | |||
| 1106 | oid->aoi_id[4] <= UINT8_MAX0xff) { | |||
| 1107 | prefix = oid->aoi_id[4]; | |||
| 1108 | i = 5; | |||
| 1109 | } | |||
| 1110 | ||||
| 1111 | if (ax_pdu_need(ax, 4) == -1) | |||
| 1112 | return -1; | |||
| 1113 | ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i; | |||
| 1114 | ax->ax_wbuf[ax->ax_wbtlen++] = prefix; | |||
| 1115 | ax->ax_wbuf[ax->ax_wbtlen++] = !!include; | |||
| 1116 | ax->ax_wbuf[ax->ax_wbtlen++] = 0; | |||
| 1117 | ||||
| 1118 | for (; i < n_subid; i++) { | |||
| 1119 | if (ax_pdu_add_uint32(ax, oid->aoi_id[i]) == -1) | |||
| 1120 | return -1; | |||
| 1121 | } | |||
| 1122 | ||||
| 1123 | return 0; | |||
| 1124 | } | |||
| 1125 | ||||
| 1126 | static int | |||
| 1127 | ax_pdu_add_str(struct ax *ax, struct ax_ostring *str) | |||
| 1128 | { | |||
| 1129 | size_t length, zeroes; | |||
| 1130 | ||||
| 1131 | if (ax_pdu_add_uint32(ax, str->aos_slen) == -1) | |||
| 1132 | return -1; | |||
| 1133 | ||||
| 1134 | if ((zeroes = (4 - (str->aos_slen % 4))) == 4) | |||
| 1135 | zeroes = 0; | |||
| 1136 | length = str->aos_slen + zeroes; | |||
| 1137 | if (ax_pdu_need(ax, length) == -1) | |||
| 1138 | return -1; | |||
| 1139 | ||||
| 1140 | memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen); | |||
| 1141 | ax->ax_wbtlen += str->aos_slen; | |||
| 1142 | memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes); | |||
| 1143 | ax->ax_wbtlen += zeroes; | |||
| 1144 | return 0; | |||
| 1145 | } | |||
| 1146 | ||||
| 1147 | static int | |||
| 1148 | ax_pdu_add_varbindlist(struct ax *ax, | |||
| 1149 | struct ax_varbind *vblist, size_t nvb) | |||
| 1150 | { | |||
| 1151 | size_t i; | |||
| 1152 | uint16_t temp; | |||
| 1153 | ||||
| 1154 | for (i = 0; i < nvb; i++) { | |||
| 1155 | temp = (uint16_t) vblist[i].avb_type; | |||
| 1156 | if (ax_pdu_add_uint16(ax, temp) == -1 || | |||
| 1157 | ax_pdu_need(ax, 2)) | |||
| 1158 | return -1; | |||
| 1159 | memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2); | |||
| 1160 | ax->ax_wbtlen += 2; | |||
| 1161 | if (ax_pdu_add_oid(ax, &(vblist[i].avb_oid), 0) == -1) | |||
| 1162 | return -1; | |||
| 1163 | switch (vblist[i].avb_type) { | |||
| 1164 | case AX_DATA_TYPE_INTEGER: | |||
| 1165 | if (ax_pdu_add_uint32(ax, | |||
| 1166 | vblist[i].avb_data.avb_int32) == -1) | |||
| 1167 | return -1; | |||
| 1168 | break; | |||
| 1169 | case AX_DATA_TYPE_COUNTER32: | |||
| 1170 | case AX_DATA_TYPE_GAUGE32: | |||
| 1171 | case AX_DATA_TYPE_TIMETICKS: | |||
| 1172 | if (ax_pdu_add_uint32(ax, | |||
| 1173 | vblist[i].avb_data.avb_uint32) == -1) | |||
| 1174 | return -1; | |||
| 1175 | break; | |||
| 1176 | case AX_DATA_TYPE_COUNTER64: | |||
| 1177 | if (ax_pdu_add_uint64(ax, | |||
| 1178 | vblist[i].avb_data.avb_uint64) == -1) | |||
| 1179 | return -1; | |||
| 1180 | break; | |||
| 1181 | case AX_DATA_TYPE_OCTETSTRING: | |||
| 1182 | case AX_DATA_TYPE_IPADDRESS: | |||
| 1183 | case AX_DATA_TYPE_OPAQUE: | |||
| 1184 | if (ax_pdu_add_str(ax, | |||
| 1185 | &(vblist[i].avb_data.avb_ostring)) == -1) | |||
| 1186 | return -1; | |||
| 1187 | break; | |||
| 1188 | case AX_DATA_TYPE_OID: | |||
| 1189 | if (ax_pdu_add_oid(ax, | |||
| 1190 | &(vblist[i].avb_data.avb_oid), 1) == -1) | |||
| 1191 | return -1; | |||
| 1192 | break; | |||
| 1193 | case AX_DATA_TYPE_NULL: | |||
| 1194 | case AX_DATA_TYPE_NOSUCHOBJECT: | |||
| 1195 | case AX_DATA_TYPE_NOSUCHINSTANCE: | |||
| 1196 | case AX_DATA_TYPE_ENDOFMIBVIEW: | |||
| 1197 | break; | |||
| 1198 | default: | |||
| 1199 | errno(*__errno()) = EINVAL22; | |||
| 1200 | return -1; | |||
| 1201 | } | |||
| 1202 | } | |||
| 1203 | return 0; | |||
| 1204 | } | |||
| 1205 | ||||
| 1206 | static uint16_t | |||
| 1207 | ax_pdutoh16(struct ax_pdu_header *header, uint8_t *buf) | |||
| 1208 | { | |||
| 1209 | uint16_t value; | |||
| 1210 | ||||
| 1211 | memcpy(&value, buf, sizeof(value)); | |||
| 1212 | if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER(1 << 4)) | |||
| 1213 | return be16toh(value)(__uint16_t)(__builtin_constant_p(value) ? (__uint16_t)(((__uint16_t )(value) & 0xffU) << 8 | ((__uint16_t)(value) & 0xff00U) >> 8) : __swap16md(value)); | |||
| 1214 | return le16toh(value)((__uint16_t)(value)); | |||
| 1215 | } | |||
| 1216 | ||||
| 1217 | static uint32_t | |||
| 1218 | ax_pdutoh32(struct ax_pdu_header *header, uint8_t *buf) | |||
| 1219 | { | |||
| 1220 | uint32_t value; | |||
| 1221 | ||||
| 1222 | memcpy(&value, buf, sizeof(value)); | |||
| 1223 | if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER(1 << 4)) | |||
| 1224 | return be32toh(value)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t )(value) & 0xff) << 24 | ((__uint32_t)(value) & 0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >> 8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md (value)); | |||
| 1225 | return le32toh(value)((__uint32_t)(value)); | |||
| 1226 | } | |||
| 1227 | ||||
| 1228 | static uint64_t | |||
| 1229 | ax_pdutoh64(struct ax_pdu_header *header, uint8_t *buf) | |||
| 1230 | { | |||
| 1231 | uint64_t value; | |||
| 1232 | ||||
| 1233 | memcpy(&value, buf, sizeof(value)); | |||
| 1234 | if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER(1 << 4)) | |||
| 1235 | return be64toh(value)(__uint64_t)(__builtin_constant_p(value) ? (__uint64_t)((((__uint64_t )(value) & 0xff) << 56) | ((__uint64_t)(value) & 0xff00ULL) << 40 | ((__uint64_t)(value) & 0xff0000ULL ) << 24 | ((__uint64_t)(value) & 0xff000000ULL) << 8 | ((__uint64_t)(value) & 0xff00000000ULL) >> 8 | ((__uint64_t)(value) & 0xff0000000000ULL) >> 24 | ( (__uint64_t)(value) & 0xff000000000000ULL) >> 40 | ( (__uint64_t)(value) & 0xff00000000000000ULL) >> 56) : __swap64md(value)); | |||
| 1236 | return le64toh(value)((__uint64_t)(value)); | |||
| 1237 | } | |||
| 1238 | ||||
| 1239 | static ssize_t | |||
| 1240 | ax_pdutooid(struct ax_pdu_header *header, struct ax_oid *oid, | |||
| 1241 | uint8_t *buf, size_t rawlen) | |||
| 1242 | { | |||
| 1243 | size_t i = 0; | |||
| 1244 | ssize_t nread; | |||
| 1245 | ||||
| 1246 | if (rawlen < 4) | |||
| 1247 | goto fail; | |||
| 1248 | rawlen -= 4; | |||
| 1249 | nread = 4; | |||
| 1250 | oid->aoi_idlen = *buf++; | |||
| 1251 | if (rawlen < (oid->aoi_idlen * 4)) | |||
| 1252 | goto fail; | |||
| 1253 | nread += oid->aoi_idlen * 4; | |||
| 1254 | if (*buf != 0) { | |||
| 1255 | oid->aoi_id[0] = 1; | |||
| 1256 | oid->aoi_id[1] = 3; | |||
| 1257 | oid->aoi_id[2] = 6; | |||
| 1258 | oid->aoi_id[3] = 1; | |||
| 1259 | oid->aoi_id[4] = *buf; | |||
| 1260 | oid->aoi_idlen += 5; | |||
| 1261 | i = 5; | |||
| 1262 | } | |||
| 1263 | buf++; | |||
| 1264 | oid->aoi_include = *buf; | |||
| 1265 | for (buf += 2; i < oid->aoi_idlen; i++, buf += 4) | |||
| 1266 | oid->aoi_id[i] = ax_pdutoh32(header, buf); | |||
| 1267 | ||||
| 1268 | return nread; | |||
| 1269 | ||||
| 1270 | fail: | |||
| 1271 | errno(*__errno()) = EPROTO95; | |||
| 1272 | return -1; | |||
| 1273 | } | |||
| 1274 | ||||
| 1275 | static ssize_t | |||
| 1276 | ax_pdutoostring(struct ax_pdu_header *header, | |||
| 1277 | struct ax_ostring *ostring, uint8_t *buf, size_t rawlen) | |||
| 1278 | { | |||
| 1279 | ssize_t nread; | |||
| 1280 | ||||
| 1281 | if (rawlen < 4) | |||
| 1282 | goto fail; | |||
| 1283 | ||||
| 1284 | ostring->aos_slen = ax_pdutoh32(header, buf); | |||
| 1285 | rawlen -= 4; | |||
| 1286 | buf += 4; | |||
| 1287 | if (ostring->aos_slen > rawlen) | |||
| 1288 | goto fail; | |||
| 1289 | if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL((void *)0)) | |||
| 1290 | return -1; | |||
| 1291 | memcpy(ostring->aos_string, buf, ostring->aos_slen); | |||
| 1292 | ostring->aos_string[ostring->aos_slen] = '\0'; | |||
| 1293 | ||||
| 1294 | nread = 4 + ostring->aos_slen; | |||
| 1295 | if (ostring->aos_slen % 4 != 0) | |||
| 1296 | nread += 4 - (ostring->aos_slen % 4); | |||
| 1297 | ||||
| 1298 | return nread; | |||
| 1299 | ||||
| 1300 | fail: | |||
| 1301 | errno(*__errno()) = EPROTO95; | |||
| 1302 | return -1; | |||
| 1303 | } | |||
| 1304 | ||||
| 1305 | static ssize_t | |||
| 1306 | ax_pdutovarbind(struct ax_pdu_header *header, | |||
| 1307 | struct ax_varbind *varbind, uint8_t *buf, size_t rawlen) | |||
| 1308 | { | |||
| 1309 | ssize_t nread, rread = 4; | |||
| 1310 | ||||
| 1311 | if (rawlen == 0) | |||
| 1312 | return 0; | |||
| 1313 | ||||
| 1314 | if (rawlen < 8) | |||
| 1315 | goto fail; | |||
| 1316 | varbind->avb_type = ax_pdutoh16(header, buf); | |||
| 1317 | ||||
| 1318 | buf += 4; | |||
| 1319 | rawlen -= 4; | |||
| 1320 | nread = ax_pdutooid(header, &(varbind->avb_oid), buf, rawlen); | |||
| 1321 | if (nread == -1) | |||
| 1322 | return -1; | |||
| 1323 | rread += nread; | |||
| 1324 | buf += nread; | |||
| 1325 | rawlen -= nread; | |||
| 1326 | ||||
| 1327 | switch(varbind->avb_type) { | |||
| 1328 | case AX_DATA_TYPE_INTEGER: | |||
| 1329 | if (rawlen < 4) | |||
| 1330 | goto fail; | |||
| 1331 | varbind->avb_data.avb_int32 = ax_pdutoh32(header, buf); | |||
| 1332 | return rread + 4; | |||
| 1333 | case AX_DATA_TYPE_COUNTER32: | |||
| 1334 | case AX_DATA_TYPE_GAUGE32: | |||
| 1335 | case AX_DATA_TYPE_TIMETICKS: | |||
| 1336 | if (rawlen < 4) | |||
| 1337 | goto fail; | |||
| 1338 | varbind->avb_data.avb_uint32 = ax_pdutoh32(header, buf); | |||
| 1339 | return rread + 4; | |||
| 1340 | case AX_DATA_TYPE_COUNTER64: | |||
| 1341 | if (rawlen < 8) | |||
| 1342 | goto fail; | |||
| 1343 | varbind->avb_data.avb_uint64 = ax_pdutoh64(header, buf); | |||
| 1344 | return rread + 8; | |||
| 1345 | case AX_DATA_TYPE_OCTETSTRING: | |||
| 1346 | case AX_DATA_TYPE_IPADDRESS: | |||
| 1347 | case AX_DATA_TYPE_OPAQUE: | |||
| 1348 | nread = ax_pdutoostring(header, | |||
| 1349 | &(varbind->avb_data.avb_ostring), buf, rawlen); | |||
| 1350 | if (nread == -1) | |||
| 1351 | return -1; | |||
| 1352 | return nread + rread; | |||
| 1353 | case AX_DATA_TYPE_OID: | |||
| 1354 | nread = ax_pdutooid(header, &(varbind->avb_data.avb_oid), | |||
| 1355 | buf, rawlen); | |||
| 1356 | if (nread == -1) | |||
| 1357 | return -1; | |||
| 1358 | return nread + rread; | |||
| 1359 | case AX_DATA_TYPE_NULL: | |||
| 1360 | case AX_DATA_TYPE_NOSUCHOBJECT: | |||
| 1361 | case AX_DATA_TYPE_NOSUCHINSTANCE: | |||
| 1362 | case AX_DATA_TYPE_ENDOFMIBVIEW: | |||
| 1363 | return rread; | |||
| 1364 | } | |||
| 1365 | ||||
| 1366 | fail: | |||
| 1367 | errno(*__errno()) = EPROTO95; | |||
| 1368 | return -1; | |||
| 1369 | } |