snmp_asn1.c: Fix handling of u64 values

This commit is contained in:
Dirk Ziegelmeier 2017-07-26 12:48:19 +02:00
parent 0dabc8df9b
commit 0d23d686eb
3 changed files with 21 additions and 44 deletions

View File

@ -465,7 +465,8 @@ snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value
if (data & 0x80) { if (data & 0x80) {
/* negative, start from -1 */ /* negative, start from -1 */
*value = (-1 << 8) | data; *value = -1;
*value = (*value << 8) | data;
} else { } else {
/* positive, start from 0 */ /* positive, start from 0 */
*value = data; *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 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value * 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 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 */ /* check if high u32 is 0 */
if (*value == 0x00) { if ((value >> 32) == 0) {
/* only low u32 is important */ /* only low u32 is important */
value++; snmp_asn1_enc_u32t_cnt((u32_t)value, octets_needed);
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
} else { } else {
/* low u32 does not matter for length determination */ /* 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 */ *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 pbuf_stream points to a pbuf stream
* @param len length of the coded integer field * @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 * @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 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value * 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 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; u8_t data;
if (len <= 4) {
/* high u32 is 0 */
*value = 0;
/* directly skip to low u32 */
value++;
}
if ((len > 0) && (len <= 9)) { if ((len > 0) && (len <= 9)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); 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) { while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
*value <<= 8;
if (len == 4) {
/* skip to low u32 */
value++;
*value = 0;
} else {
*value <<= 8;
}
*value |= data; *value |= data;
len--; 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 pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) * @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 * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
* *
* @see snmp_asn1_enc_u64t_cnt() * @see snmp_asn1_enc_u64t_cnt()
*/ */
err_t 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) { if (octets_needed > 9) {
return ERR_ARG; return ERR_ARG;
@ -704,21 +689,13 @@ snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, co
octets_needed--; 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) { while (octets_needed > 1) {
octets_needed--; 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) */ /* 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; return ERR_OK;
} }

View File

@ -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); err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len);
#if LWIP_HAVE_INT64 #if LWIP_HAVE_INT64
err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, 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(const u32_t *value, u16_t *octets_needed); 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, const u32_t* value); err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u64_t value);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -1521,7 +1521,7 @@ snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len)
if (varbind->value_len != sizeof(u64_t)) { if (varbind->value_len != sizeof(u64_t)) {
return ERR_VAL; 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; break;
#endif #endif
default: default:
@ -1596,7 +1596,7 @@ snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_v
break; break;
#if LWIP_HAVE_INT64 #if LWIP_HAVE_INT64
case SNMP_ASN1_TYPE_COUNTER64: 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; break;
#endif #endif
default: default:
@ -1944,7 +1944,7 @@ snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct s
break; break;
#if LWIP_HAVE_INT64 #if LWIP_HAVE_INT64
case SNMP_ASN1_TYPE_COUNTER64: 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); varbind->value_len = sizeof(u64_t);
break; break;
#endif #endif