123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749 |
- /**
- * @file
- * Abstract Syntax Notation One (ISO 8824, 8825) encoding
- *
- * @todo not optimised (yet), favor correctness over speed, favor speed over size
- */
- /*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * Author: Christiaan Simons <christiaan.simons@axon.tv>
- * Martin Hentschel <info@cl-soft.de>
- */
- #include "lwip/apps/snmp_opts.h"
- #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
- #include "snmp_asn1.h"
- #define PBUF_OP_EXEC(code) \
- if ((code) != ERR_OK) { \
- return ERR_BUF; \
- }
- /**
- * Encodes a TLV into a pbuf stream.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param tlv TLV to encode
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
- */
- err_t
- snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
- {
- u8_t data;
- u8_t length_bytes_required;
- /* write type */
- if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
- /* extended format is not used by SNMP so we do not accept those values */
- return ERR_ARG;
- }
- if (tlv->type_len != 0) {
- /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
- return ERR_ARG;
- }
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
- tlv->type_len = 1;
- /* write length */
- if (tlv->value_len <= 127) {
- length_bytes_required = 1;
- } else if (tlv->value_len <= 255) {
- length_bytes_required = 2;
- } else {
- length_bytes_required = 3;
- }
- /* check for forced min length */
- if (tlv->length_len > 0) {
- if (tlv->length_len < length_bytes_required) {
- /* unable to code requested length in requested number of bytes */
- return ERR_ARG;
- }
- length_bytes_required = tlv->length_len;
- } else {
- tlv->length_len = length_bytes_required;
- }
- if (length_bytes_required > 1) {
- /* multi byte representation required */
- length_bytes_required--;
- data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
- while (length_bytes_required > 1) {
- if (length_bytes_required == 2) {
- /* append high byte */
- data = (u8_t)(tlv->value_len >> 8);
- } else {
- /* append leading 0x00 */
- data = 0x00;
- }
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
- length_bytes_required--;
- }
- }
- /* append low byte */
- data = (u8_t)(tlv->value_len & 0xFF);
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
- return ERR_OK;
- }
- /**
- * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param raw_len raw data length
- * @param raw points raw data
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
- */
- err_t
- snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
- {
- PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
- return ERR_OK;
- }
- /**
- * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
- * @param value is the host order u32_t value to be encoded
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
- *
- * @see snmp_asn1_enc_u32t_cnt()
- */
- err_t
- snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
- {
- if (octets_needed > 5) {
- return ERR_ARG;
- }
- if (octets_needed == 5) {
- /* not enough bits in 'value' add leading 0x00 */
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
- octets_needed--;
- }
- while (octets_needed > 1) {
- octets_needed--;
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
- }
- /* (only) one least significant octet */
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
- return ERR_OK;
- }
- /**
- * Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
- * @param value is the host order u32_t value to be encoded
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
- *
- * @see snmp_asn1_enc_u64t_cnt()
- */
- err_t
- snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
- {
- if (octets_needed > 9) {
- return ERR_ARG;
- }
- if (octets_needed == 9) {
- /* not enough bits in 'value' add leading 0x00 */
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
- octets_needed--;
- }
- while (octets_needed > 4) {
- octets_needed--;
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
- }
- /* skip to low u32 */
- value++;
- while (octets_needed > 1) {
- octets_needed--;
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
- }
- /* always write at least one octet (also in case of value == 0) */
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
- return ERR_OK;
- }
- /**
- * Encodes s32_t integer into a pbuf chained ASN1 msg.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
- * @param value is the host order s32_t value to be encoded
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
- *
- * @see snmp_asn1_enc_s32t_cnt()
- */
- err_t
- snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
- {
- while (octets_needed > 1) {
- octets_needed--;
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
- }
- /* (only) one least significant octet */
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
- return ERR_OK;
- }
- /**
- * Encodes object identifier into a pbuf chained ASN1 msg.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param oid points to object identifier array
- * @param oid_len object identifier array length
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
- */
- err_t
- snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
- {
- if (oid_len > 1) {
- /* write compressed first two sub id's */
- u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
- oid_len -= 2;
- oid += 2;
- } else {
- /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
- /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
- return ERR_ARG;
- }
- while (oid_len > 0) {
- u32_t sub_id;
- u8_t shift, tail;
- oid_len--;
- sub_id = *oid;
- tail = 0;
- shift = 28;
- while (shift > 0) {
- u8_t code;
- code = (u8_t)(sub_id >> shift);
- if ((code != 0) || (tail != 0)) {
- tail = 1;
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
- }
- shift -= 7;
- }
- PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
- /* proceed to next sub-identifier */
- oid++;
- }
- return ERR_OK;
- }
- /**
- * Returns octet count for length.
- *
- * @param length parameter length
- * @param octets_needed points to the return value
- */
- void
- snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
- {
- if (length < 0x80U) {
- *octets_needed = 1;
- } else if (length < 0x100U) {
- *octets_needed = 2;
- } else {
- *octets_needed = 3;
- }
- }
- /**
- * Returns octet count for an u32_t.
- *
- * @param value value to be encoded
- * @param octets_needed points to the return value
- *
- * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
- * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
- * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
- */
- void
- snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
- {
- if (value < 0x80UL) {
- *octets_needed = 1;
- } else if (value < 0x8000UL) {
- *octets_needed = 2;
- } else if (value < 0x800000UL) {
- *octets_needed = 3;
- } else if (value < 0x80000000UL) {
- *octets_needed = 4;
- } else {
- *octets_needed = 5;
- }
- }
- /**
- * Returns octet count for an u64_t.
- *
- * @param value value to be encoded
- * @param octets_needed points to the return value
- *
- * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
- * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
- * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
- */
- void
- snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
- {
- /* check if high u32 is 0 */
- if (*value == 0x00) {
- /* only low u32 is important */
- value++;
- snmp_asn1_enc_u32t_cnt(*value, octets_needed);
- } else {
- /* low u32 does not matter for length determination */
- snmp_asn1_enc_u32t_cnt(*value, octets_needed);
- *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
- }
- }
- /**
- * Returns octet count for an s32_t.
- *
- * @param value value to be encoded
- * @param octets_needed points to the return value
- *
- * @note ASN coded integers are _always_ signed.
- */
- void
- snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
- {
- if (value < 0) {
- value = ~value;
- }
- if (value < 0x80L) {
- *octets_needed = 1;
- } else if (value < 0x8000L) {
- *octets_needed = 2;
- } else if (value < 0x800000L) {
- *octets_needed = 3;
- } else {
- *octets_needed = 4;
- }
- }
- /**
- * Returns octet count for an object identifier.
- *
- * @param oid points to object identifier array
- * @param oid_len object identifier array length
- * @param octets_needed points to the return value
- */
- void
- snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
- {
- u32_t sub_id;
- *octets_needed = 0;
- if (oid_len > 1) {
- /* compressed prefix in one octet */
- (*octets_needed)++;
- oid_len -= 2;
- oid += 2;
- }
- while (oid_len > 0) {
- oid_len--;
- sub_id = *oid;
- sub_id >>= 7;
- (*octets_needed)++;
- while (sub_id > 0) {
- sub_id >>= 7;
- (*octets_needed)++;
- }
- oid++;
- }
- }
- /**
- * Decodes a TLV from a pbuf stream.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param tlv returns decoded TLV
- * @return ERR_OK if successful, ERR_VAL if we can't decode
- */
- err_t
- snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
- {
- u8_t data;
- /* decode type first */
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- tlv->type = data;
- if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
- /* extended format is not used by SNMP so we do not accept those values */
- return ERR_VAL;
- }
- tlv->type_len = 1;
- /* now, decode length */
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- if (data < 0x80) { /* short form */
- tlv->length_len = 1;
- tlv->value_len = data;
- } else if (data > 0x80) { /* long form */
- u8_t length_bytes = data - 0x80;
- tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
- tlv->value_len = 0;
- while (length_bytes > 0) {
- /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
- if (tlv->value_len > 0xFF) {
- return ERR_VAL;
- }
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- tlv->value_len <<= 8;
- tlv->value_len |= data;
- /* take care for special value used for indefinite length */
- if (tlv->value_len == 0xFFFF) {
- return ERR_VAL;
- }
- length_bytes--;
- }
- } else { /* data == 0x80 indefinite length form */
- /* (not allowed for SNMP; RFC 1157, 3.2.2) */
- return ERR_VAL;
- }
- return ERR_OK;
- }
- /**
- * Decodes positive integer (counter, gauge, timeticks) into u32_t.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param len length of the coded integer field
- * @param value return host order integer
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
- *
- * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
- * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
- * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
- */
- err_t
- snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
- {
- u8_t data;
- if ((len > 0) && (len <= 5)) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- /* expecting sign bit to be zero, only unsigned please! */
- if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
- *value = data;
- len--;
- while (len > 0) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- len--;
- *value <<= 8;
- *value |= data;
- }
- return ERR_OK;
- }
- }
- return ERR_VAL;
- }
- /**
- * Decodes large positive integer (counter64) into 2x u32_t.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param len length of the coded integer field
- * @param value return host order integer
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
- *
- * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
- * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
- * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
- */
- err_t
- snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
- {
- u8_t data;
- if (len <= 4) {
- /* high u32 is 0 */
- *value = 0;
- /* directly skip to low u32 */
- value++;
- }
- if ((len > 0) && (len <= 9)) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- /* expecting sign bit to be zero, only unsigned please! */
- if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
- *value = data;
- len--;
- while (len > 0) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- if (len == 4) {
- /* skip to low u32 */
- value++;
- *value = 0;
- } else {
- *value <<= 8;
- }
- *value |= data;
- len--;
- }
- return ERR_OK;
- }
- }
- return ERR_VAL;
- }
- /**
- * Decodes integer into s32_t.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param len length of the coded integer field
- * @param value return host order integer
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
- *
- * @note ASN coded integers are _always_ signed!
- */
- err_t
- snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
- {
- #if BYTE_ORDER == LITTLE_ENDIAN
- u8_t *lsb_ptr = (u8_t*)value;
- #endif
- #if BYTE_ORDER == BIG_ENDIAN
- u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
- #endif
- u8_t sign;
- u8_t data;
- if ((len > 0) && (len < 5)) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- len--;
- if (data & 0x80) {
- /* negative, start from -1 */
- *value = -1;
- sign = 1;
- *lsb_ptr &= data;
- } else {
- /* positive, start from 0 */
- *value = 0;
- sign = 0;
- *lsb_ptr |= data;
- }
- /* OR/AND octets with value */
- while (len > 0) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- len--;
- #if BYTE_ORDER == LITTLE_ENDIAN
- *value <<= 8;
- #endif
- #if BYTE_ORDER == BIG_ENDIAN
- *value >>= 8;
- #endif
- if (sign) {
- *lsb_ptr |= 255;
- *lsb_ptr &= data;
- } else {
- *lsb_ptr |= data;
- }
- }
- return ERR_OK;
- }
- return ERR_VAL;
- }
- /**
- * Decodes object identifier from incoming message into array of u32_t.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param len length of the coded object identifier
- * @param oid return decoded object identifier
- * @param oid_len return decoded object identifier length
- * @param oid_max_len size of oid buffer
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
- */
- err_t
- 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)
- {
- u32_t *oid_ptr;
- u8_t data;
- *oid_len = 0;
- oid_ptr = oid;
- if (len > 0) {
- if (oid_max_len < 2) {
- return ERR_MEM;
- }
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- len--;
- /* first compressed octet */
- if (data == 0x2B) {
- /* (most) common case 1.3 (iso.org) */
- *oid_ptr = 1;
- oid_ptr++;
- *oid_ptr = 3;
- oid_ptr++;
- } else if (data < 40) {
- *oid_ptr = 0;
- oid_ptr++;
- *oid_ptr = data;
- oid_ptr++;
- } else if (data < 80) {
- *oid_ptr = 1;
- oid_ptr++;
- *oid_ptr = data - 40;
- oid_ptr++;
- } else {
- *oid_ptr = 2;
- oid_ptr++;
- *oid_ptr = data - 80;
- oid_ptr++;
- }
- *oid_len = 2;
- } else {
- /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
- return ERR_OK;
- }
- while ((len > 0) && (*oid_len < oid_max_len)) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- len--;
- if ((data & 0x80) == 0x00) {
- /* sub-identifier uses single octet */
- *oid_ptr = data;
- } else {
- /* sub-identifier uses multiple octets */
- u32_t sub_id = (data & ~0x80);
- while ((len > 0) && ((data & 0x80) != 0)) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
- len--;
- sub_id = (sub_id << 7) + (data & ~0x80);
- }
- if ((data & 0x80) != 0) {
- /* "more bytes following" bit still set at end of len */
- return ERR_VAL;
- }
- *oid_ptr = sub_id;
- }
- oid_ptr++;
- (*oid_len)++;
- }
- if (len > 0) {
- /* OID to long to fit in our buffer */
- return ERR_MEM;
- }
- return ERR_OK;
- }
- /**
- * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
- * from incoming message into array.
- *
- * @param pbuf_stream points to a pbuf stream
- * @param len length of the coded raw data (zero is valid, e.g. empty string!)
- * @param buf return raw bytes
- * @param buf_len returns length of the raw return value
- * @param buf_max_len buffer size
- * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
- */
- err_t
- 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)
- {
- if (len > buf_max_len) {
- /* not enough dst space */
- return ERR_MEM;
- }
- *buf_len = len;
- while (len > 0) {
- PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
- buf++;
- len--;
- }
- return ERR_OK;
- }
- #endif /* LWIP_SNMP */
|