1 /** 2 * @file 3 * Abstract Syntax Notation One (ISO 8824, 8825) encoding 4 * 5 * @todo not optimised (yet), favor correctness over speed, favor speed over size 6 */ 7 8 /* 9 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without modification, 13 * are permitted provided that the following conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright notice, 16 * this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright notice, 18 * this list of conditions and the following disclaimer in the documentation 19 * and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 26 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 28 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 * OF SUCH DAMAGE. 33 * 34 * Author: Christiaan Simons <christiaan.simons@axon.tv> 35 * Martin Hentschel <info@cl-soft.de> 36 */ 37 38 #include "lwip/apps/snmp_opts.h" 39 40 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 41 42 #include "snmp_asn1.h" 43 44 #define PBUF_OP_EXEC(code) \ 45 if ((code) != ERR_OK) { \ 46 return ERR_BUF; \ 47 } 48 49 /** 50 * Encodes a TLV into a pbuf stream. 51 * 52 * @param pbuf_stream points to a pbuf stream 53 * @param tlv TLV to encode 54 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode 55 */ 56 err_t 57 snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv) 58 { 59 u8_t data; 60 u8_t length_bytes_required; 61 62 /* write type */ 63 if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) { 64 /* extended format is not used by SNMP so we do not accept those values */ 65 return ERR_ARG; 66 } 67 if (tlv->type_len != 0) { 68 /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */ 69 return ERR_ARG; 70 } 71 72 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type)); 73 tlv->type_len = 1; 74 75 /* write length */ 76 if (tlv->value_len <= 127) { 77 length_bytes_required = 1; 78 } else if (tlv->value_len <= 255) { 79 length_bytes_required = 2; 80 } else { 81 length_bytes_required = 3; 82 } 83 84 /* check for forced min length */ 85 if (tlv->length_len > 0) { 86 if (tlv->length_len < length_bytes_required) { 87 /* unable to code requested length in requested number of bytes */ 88 return ERR_ARG; 89 } 90 91 length_bytes_required = tlv->length_len; 92 } else { 93 tlv->length_len = length_bytes_required; 94 } 95 96 if (length_bytes_required > 1) { 97 /* multi byte representation required */ 98 length_bytes_required--; 99 data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */ 100 101 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); 102 103 while (length_bytes_required > 1) { 104 if (length_bytes_required == 2) { 105 /* append high byte */ 106 data = (u8_t)(tlv->value_len >> 8); 107 } else { 108 /* append leading 0x00 */ 109 data = 0x00; 110 } 111 112 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); 113 length_bytes_required--; 114 } 115 } 116 117 /* append low byte */ 118 data = (u8_t)(tlv->value_len & 0xFF); 119 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); 120 121 return ERR_OK; 122 } 123 124 /** 125 * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. 126 * 127 * @param pbuf_stream points to a pbuf stream 128 * @param raw_len raw data length 129 * @param raw points raw data 130 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode 131 */ 132 err_t 133 snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len) 134 { 135 PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len)); 136 137 return ERR_OK; 138 } 139 140 /** 141 * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. 142 * 143 * @param pbuf_stream points to a pbuf stream 144 * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) 145 * @param value is the host order u32_t value to be encoded 146 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode 147 * 148 * @see snmp_asn1_enc_u32t_cnt() 149 */ 150 err_t 151 snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value) 152 { 153 if (octets_needed > 5) { 154 return ERR_ARG; 155 } 156 if (octets_needed == 5) { 157 /* not enough bits in 'value' add leading 0x00 */ 158 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00)); 159 octets_needed--; 160 } 161 162 while (octets_needed > 1) { 163 octets_needed--; 164 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3)))); 165 } 166 167 /* (only) one least significant octet */ 168 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value)); 169 170 return ERR_OK; 171 } 172 173 /** 174 * Encodes u64_t (counter64) into a pbuf chained ASN1 msg. 175 * 176 * @param pbuf_stream points to a pbuf stream 177 * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) 178 * @param value is the host order u32_t value to be encoded 179 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode 180 * 181 * @see snmp_asn1_enc_u64t_cnt() 182 */ 183 err_t 184 snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value) 185 { 186 if (octets_needed > 9) { 187 return ERR_ARG; 188 } 189 if (octets_needed == 9) { 190 /* not enough bits in 'value' add leading 0x00 */ 191 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00)); 192 octets_needed--; 193 } 194 195 while (octets_needed > 4) { 196 octets_needed--; 197 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3)))); 198 } 199 200 /* skip to low u32 */ 201 value++; 202 203 while (octets_needed > 1) { 204 octets_needed--; 205 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3)))); 206 } 207 208 /* always write at least one octet (also in case of value == 0) */ 209 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value))); 210 211 return ERR_OK; 212 } 213 214 /** 215 * Encodes s32_t integer into a pbuf chained ASN1 msg. 216 * 217 * @param pbuf_stream points to a pbuf stream 218 * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) 219 * @param value is the host order s32_t value to be encoded 220 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode 221 * 222 * @see snmp_asn1_enc_s32t_cnt() 223 */ 224 err_t 225 snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value) 226 { 227 while (octets_needed > 1) { 228 octets_needed--; 229 230 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3)))); 231 } 232 233 /* (only) one least significant octet */ 234 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value)); 235 236 return ERR_OK; 237 } 238 239 /** 240 * Encodes object identifier into a pbuf chained ASN1 msg. 241 * 242 * @param pbuf_stream points to a pbuf stream 243 * @param oid points to object identifier array 244 * @param oid_len object identifier array length 245 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode 246 */ 247 err_t 248 snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len) 249 { 250 if (oid_len > 1) { 251 /* write compressed first two sub id's */ 252 u32_t compressed_byte = ((oid[0] * 40) + oid[1]); 253 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte)); 254 oid_len -= 2; 255 oid += 2; 256 } else { 257 /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */ 258 /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ 259 return ERR_ARG; 260 } 261 262 while (oid_len > 0) { 263 u32_t sub_id; 264 u8_t shift, tail; 265 266 oid_len--; 267 sub_id = *oid; 268 tail = 0; 269 shift = 28; 270 while (shift > 0) { 271 u8_t code; 272 273 code = (u8_t)(sub_id >> shift); 274 if ((code != 0) || (tail != 0)) { 275 tail = 1; 276 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80)); 277 } 278 shift -= 7; 279 } 280 PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F)); 281 282 /* proceed to next sub-identifier */ 283 oid++; 284 } 285 return ERR_OK; 286 } 287 288 /** 289 * Returns octet count for length. 290 * 291 * @param length parameter length 292 * @param octets_needed points to the return value 293 */ 294 void 295 snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) 296 { 297 if (length < 0x80U) { 298 *octets_needed = 1; 299 } else if (length < 0x100U) { 300 *octets_needed = 2; 301 } else { 302 *octets_needed = 3; 303 } 304 } 305 306 /** 307 * Returns octet count for an u32_t. 308 * 309 * @param value value to be encoded 310 * @param octets_needed points to the return value 311 * 312 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded 313 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value 314 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! 315 */ 316 void 317 snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) 318 { 319 if (value < 0x80UL) { 320 *octets_needed = 1; 321 } else if (value < 0x8000UL) { 322 *octets_needed = 2; 323 } else if (value < 0x800000UL) { 324 *octets_needed = 3; 325 } else if (value < 0x80000000UL) { 326 *octets_needed = 4; 327 } else { 328 *octets_needed = 5; 329 } 330 } 331 332 /** 333 * Returns octet count for an u64_t. 334 * 335 * @param value value to be encoded 336 * @param octets_needed points to the return value 337 * 338 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded 339 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value 340 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! 341 */ 342 void 343 snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed) 344 { 345 /* check if high u32 is 0 */ 346 if (*value == 0x00) { 347 /* only low u32 is important */ 348 value++; 349 snmp_asn1_enc_u32t_cnt(*value, octets_needed); 350 } else { 351 /* low u32 does not matter for length determination */ 352 snmp_asn1_enc_u32t_cnt(*value, octets_needed); 353 *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */ 354 } 355 } 356 357 /** 358 * Returns octet count for an s32_t. 359 * 360 * @param value value to be encoded 361 * @param octets_needed points to the return value 362 * 363 * @note ASN coded integers are _always_ signed. 364 */ 365 void 366 snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) 367 { 368 if (value < 0) { 369 value = ~value; 370 } 371 if (value < 0x80L) { 372 *octets_needed = 1; 373 } else if (value < 0x8000L) { 374 *octets_needed = 2; 375 } else if (value < 0x800000L) { 376 *octets_needed = 3; 377 } else { 378 *octets_needed = 4; 379 } 380 } 381 382 /** 383 * Returns octet count for an object identifier. 384 * 385 * @param oid points to object identifier array 386 * @param oid_len object identifier array length 387 * @param octets_needed points to the return value 388 */ 389 void 390 snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed) 391 { 392 u32_t sub_id; 393 394 *octets_needed = 0; 395 if (oid_len > 1) { 396 /* compressed prefix in one octet */ 397 (*octets_needed)++; 398 oid_len -= 2; 399 oid += 2; 400 } 401 while (oid_len > 0) { 402 oid_len--; 403 sub_id = *oid; 404 405 sub_id >>= 7; 406 (*octets_needed)++; 407 while (sub_id > 0) { 408 sub_id >>= 7; 409 (*octets_needed)++; 410 } 411 oid++; 412 } 413 } 414 415 /** 416 * Decodes a TLV from a pbuf stream. 417 * 418 * @param pbuf_stream points to a pbuf stream 419 * @param tlv returns decoded TLV 420 * @return ERR_OK if successful, ERR_VAL if we can't decode 421 */ 422 err_t 423 snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv) 424 { 425 u8_t data; 426 427 /* decode type first */ 428 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 429 tlv->type = data; 430 431 if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) { 432 /* extended format is not used by SNMP so we do not accept those values */ 433 return ERR_VAL; 434 } 435 tlv->type_len = 1; 436 437 /* now, decode length */ 438 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 439 440 if (data < 0x80) { /* short form */ 441 tlv->length_len = 1; 442 tlv->value_len = data; 443 } else if (data > 0x80) { /* long form */ 444 u8_t length_bytes = data - 0x80; 445 tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */ 446 tlv->value_len = 0; 447 448 while (length_bytes > 0) { 449 /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */ 450 if (tlv->value_len > 0xFF) { 451 return ERR_VAL; 452 } 453 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 454 tlv->value_len <<= 8; 455 tlv->value_len |= data; 456 457 /* take care for special value used for indefinite length */ 458 if (tlv->value_len == 0xFFFF) { 459 return ERR_VAL; 460 } 461 462 length_bytes--; 463 } 464 } else { /* data == 0x80 indefinite length form */ 465 /* (not allowed for SNMP; RFC 1157, 3.2.2) */ 466 return ERR_VAL; 467 } 468 469 return ERR_OK; 470 } 471 472 /** 473 * Decodes positive integer (counter, gauge, timeticks) into u32_t. 474 * 475 * @param pbuf_stream points to a pbuf stream 476 * @param len length of the coded integer field 477 * @param value return host order integer 478 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode 479 * 480 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded 481 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value 482 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! 483 */ 484 err_t 485 snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) 486 { 487 u8_t data; 488 489 if ((len > 0) && (len <= 5)) { 490 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 491 492 /* expecting sign bit to be zero, only unsigned please! */ 493 if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) { 494 *value = data; 495 len--; 496 497 while (len > 0) { 498 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 499 len--; 500 501 *value <<= 8; 502 *value |= data; 503 } 504 505 return ERR_OK; 506 } 507 } 508 509 return ERR_VAL; 510 } 511 512 /** 513 * Decodes large positive integer (counter64) into 2x u32_t. 514 * 515 * @param pbuf_stream points to a pbuf stream 516 * @param len length of the coded integer field 517 * @param value return host order integer 518 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode 519 * 520 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded 521 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value 522 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! 523 */ 524 err_t 525 snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) 526 { 527 u8_t data; 528 529 if (len <= 4) { 530 /* high u32 is 0 */ 531 *value = 0; 532 /* directly skip to low u32 */ 533 value++; 534 } 535 536 if ((len > 0) && (len <= 9)) { 537 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 538 539 /* expecting sign bit to be zero, only unsigned please! */ 540 if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) { 541 *value = data; 542 len--; 543 544 while (len > 0) { 545 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 546 547 if (len == 4) { 548 /* skip to low u32 */ 549 value++; 550 *value = 0; 551 } else { 552 *value <<= 8; 553 } 554 555 *value |= data; 556 len--; 557 } 558 559 return ERR_OK; 560 } 561 } 562 563 return ERR_VAL; 564 } 565 566 /** 567 * Decodes integer into s32_t. 568 * 569 * @param pbuf_stream points to a pbuf stream 570 * @param len length of the coded integer field 571 * @param value return host order integer 572 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode 573 * 574 * @note ASN coded integers are _always_ signed! 575 */ 576 err_t 577 snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value) 578 { 579 #if BYTE_ORDER == LITTLE_ENDIAN 580 u8_t *lsb_ptr = (u8_t*)value; 581 #endif 582 #if BYTE_ORDER == BIG_ENDIAN 583 u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; 584 #endif 585 u8_t sign; 586 u8_t data; 587 588 if ((len > 0) && (len < 5)) { 589 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 590 len--; 591 592 if (data & 0x80) { 593 /* negative, start from -1 */ 594 *value = -1; 595 sign = 1; 596 *lsb_ptr &= data; 597 } else { 598 /* positive, start from 0 */ 599 *value = 0; 600 sign = 0; 601 *lsb_ptr |= data; 602 } 603 604 /* OR/AND octets with value */ 605 while (len > 0) { 606 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 607 len--; 608 609 #if BYTE_ORDER == LITTLE_ENDIAN 610 *value <<= 8; 611 #endif 612 #if BYTE_ORDER == BIG_ENDIAN 613 *value >>= 8; 614 #endif 615 616 if (sign) { 617 *lsb_ptr |= 255; 618 *lsb_ptr &= data; 619 } else { 620 *lsb_ptr |= data; 621 } 622 } 623 624 return ERR_OK; 625 } 626 627 return ERR_VAL; 628 } 629 630 /** 631 * Decodes object identifier from incoming message into array of u32_t. 632 * 633 * @param pbuf_stream points to a pbuf stream 634 * @param len length of the coded object identifier 635 * @param oid return decoded object identifier 636 * @param oid_len return decoded object identifier length 637 * @param oid_max_len size of oid buffer 638 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode 639 */ 640 err_t 641 snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len) 642 { 643 u32_t *oid_ptr; 644 u8_t data; 645 646 *oid_len = 0; 647 oid_ptr = oid; 648 if (len > 0) { 649 if (oid_max_len < 2) { 650 return ERR_MEM; 651 } 652 653 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 654 len--; 655 656 /* first compressed octet */ 657 if (data == 0x2B) { 658 /* (most) common case 1.3 (iso.org) */ 659 *oid_ptr = 1; 660 oid_ptr++; 661 *oid_ptr = 3; 662 oid_ptr++; 663 } else if (data < 40) { 664 *oid_ptr = 0; 665 oid_ptr++; 666 *oid_ptr = data; 667 oid_ptr++; 668 } else if (data < 80) { 669 *oid_ptr = 1; 670 oid_ptr++; 671 *oid_ptr = data - 40; 672 oid_ptr++; 673 } else { 674 *oid_ptr = 2; 675 oid_ptr++; 676 *oid_ptr = data - 80; 677 oid_ptr++; 678 } 679 *oid_len = 2; 680 } else { 681 /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */ 682 return ERR_OK; 683 } 684 685 while ((len > 0) && (*oid_len < oid_max_len)) { 686 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 687 len--; 688 689 if ((data & 0x80) == 0x00) { 690 /* sub-identifier uses single octet */ 691 *oid_ptr = data; 692 } else { 693 /* sub-identifier uses multiple octets */ 694 u32_t sub_id = (data & ~0x80); 695 while ((len > 0) && ((data & 0x80) != 0)) { 696 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 697 len--; 698 699 sub_id = (sub_id << 7) + (data & ~0x80); 700 } 701 702 if ((data & 0x80) != 0) { 703 /* "more bytes following" bit still set at end of len */ 704 return ERR_VAL; 705 } 706 *oid_ptr = sub_id; 707 } 708 oid_ptr++; 709 (*oid_len)++; 710 } 711 712 if (len > 0) { 713 /* OID to long to fit in our buffer */ 714 return ERR_MEM; 715 } 716 717 return ERR_OK; 718 } 719 720 /** 721 * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) 722 * from incoming message into array. 723 * 724 * @param pbuf_stream points to a pbuf stream 725 * @param len length of the coded raw data (zero is valid, e.g. empty string!) 726 * @param buf return raw bytes 727 * @param buf_len returns length of the raw return value 728 * @param buf_max_len buffer size 729 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode 730 */ 731 err_t 732 snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len) 733 { 734 if (len > buf_max_len) { 735 /* not enough dst space */ 736 return ERR_MEM; 737 } 738 *buf_len = len; 739 740 while (len > 0) { 741 PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf)); 742 buf++; 743 len--; 744 } 745 746 return ERR_OK; 747 } 748 749 #endif /* LWIP_SNMP */ 750