From 0d23d686ebff19e25df7938044d01e2921f120f5 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 26 Jul 2017 12:48:19 +0200 Subject: [PATCH] snmp_asn1.c: Fix handling of u64 values --- src/apps/snmp/snmp_asn1.c | 53 +++++++++++---------------------------- src/apps/snmp/snmp_asn1.h | 6 ++--- src/apps/snmp/snmp_msg.c | 6 ++--- 3 files changed, 21 insertions(+), 44 deletions(-) diff --git a/src/apps/snmp/snmp_asn1.c b/src/apps/snmp/snmp_asn1.c index 81a2554f..0b8ec4a1 100644 --- a/src/apps/snmp/snmp_asn1.c +++ b/src/apps/snmp/snmp_asn1.c @@ -465,7 +465,8 @@ snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value if (data & 0x80) { /* negative, start from -1 */ - *value = (-1 << 8) | data; + *value = -1; + *value = (*value << 8) | data; } else { /* positive, start from 0 */ *value = data; @@ -611,19 +612,18 @@ snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u1 * * @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!! + * of 0xFFFFFFFFFFFFFFFF is preceded with 0x00 and the length is 9 octets!! */ void -snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed) +snmp_asn1_enc_u64t_cnt(u64_t value, u16_t *octets_needed) { /* check if high u32 is 0 */ - if (*value == 0x00) { + if ((value >> 32) == 0) { /* only low u32 is important */ - value++; - snmp_asn1_enc_u32t_cnt(*value, octets_needed); + snmp_asn1_enc_u32t_cnt((u32_t)value, octets_needed); } else { /* low u32 does not matter for length determination */ - snmp_asn1_enc_u32t_cnt(*value, octets_needed); + snmp_asn1_enc_u32t_cnt((u32_t)(value >> 32), octets_needed); *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */ } } @@ -633,25 +633,18 @@ snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed) * * @param pbuf_stream points to a pbuf stream * @param len length of the coded integer field - * @param value return host order integer + * @param value return 64 bit 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!! + * of 0xFFFFFFFFFFFFFFFF is preceded with 0x00 and the length is 9 octets!! */ err_t -snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) +snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u64_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)); @@ -662,15 +655,7 @@ snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value 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 <<= 8; *value |= data; len--; } @@ -687,13 +672,13 @@ snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value * * @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 + * @param value is the 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) +snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u64_t value) { if (octets_needed > 9) { return ERR_ARG; @@ -704,21 +689,13 @@ snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, co 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)))); + 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))); + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value))); return ERR_OK; } diff --git a/src/apps/snmp/snmp_asn1.h b/src/apps/snmp/snmp_asn1.h index f57e239b..e5b9e3fc 100644 --- a/src/apps/snmp/snmp_asn1.h +++ b/src/apps/snmp/snmp_asn1.h @@ -100,9 +100,9 @@ err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_need err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len); #if LWIP_HAVE_INT64 -err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value); -void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed); -err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value); +err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u64_t *value); +void snmp_asn1_enc_u64t_cnt(u64_t value, u16_t *octets_needed); +err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u64_t value); #endif #ifdef __cplusplus diff --git a/src/apps/snmp/snmp_msg.c b/src/apps/snmp/snmp_msg.c index 72c39f90..f57c032c 100644 --- a/src/apps/snmp/snmp_msg.c +++ b/src/apps/snmp/snmp_msg.c @@ -1521,7 +1521,7 @@ snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len) if (varbind->value_len != sizeof(u64_t)) { return ERR_VAL; } - snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len); + snmp_asn1_enc_u64t_cnt(*(u64_t*)varbind->value, &len->value_value_len); break; #endif default: @@ -1596,7 +1596,7 @@ snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_v break; #if LWIP_HAVE_INT64 case SNMP_ASN1_TYPE_COUNTER64: - OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value)); + OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, *(u64_t*) varbind->value)); break; #endif default: @@ -1944,7 +1944,7 @@ snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct s break; #if LWIP_HAVE_INT64 case SNMP_ASN1_TYPE_COUNTER64: - VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); + VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u64_t*)varbind->value)); varbind->value_len = sizeof(u64_t); break; #endif