Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_snmp_asn1.c Source File

lwip_snmp_asn1.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Abstract Syntax Notation One (ISO 8824, 8825) encoding
00004  *
00005  * @todo not optimised (yet), favor correctness over speed, favor speed over size
00006  */
00007 
00008 /*
00009  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
00010  * All rights reserved.
00011  *
00012  * Redistribution and use in source and binary forms, with or without modification,
00013  * are permitted provided that the following conditions are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright notice,
00016  *    this list of conditions and the following disclaimer.
00017  * 2. Redistributions in binary form must reproduce the above copyright notice,
00018  *    this list of conditions and the following disclaimer in the documentation
00019  *    and/or other materials provided with the distribution.
00020  * 3. The name of the author may not be used to endorse or promote products
00021  *    derived from this software without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00024  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00025  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00026  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00028  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00031  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00032  * OF SUCH DAMAGE.
00033  *
00034  * Author: Christiaan Simons <christiaan.simons@axon.tv>
00035  *         Martin Hentschel <info@cl-soft.de>
00036  */
00037 
00038 #include "lwip/apps/snmp_opts.h"
00039 
00040 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
00041 
00042 #include "snmp_asn1.h"
00043 
00044 #define PBUF_OP_EXEC(code) \
00045   if ((code) != ERR_OK) { \
00046     return ERR_BUF; \
00047   }
00048 
00049 /**
00050  * Encodes a TLV into a pbuf stream.
00051  *
00052  * @param pbuf_stream points to a pbuf stream
00053  * @param tlv TLV to encode
00054  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
00055  */
00056 err_t
00057 snmp_ans1_enc_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv)
00058 {
00059   u8_t data;
00060   u8_t length_bytes_required;
00061 
00062   /* write type */
00063   if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
00064     /* extended format is not used by SNMP so we do not accept those values */
00065     return ERR_ARG;
00066   }
00067   if (tlv->type_len != 0) {
00068     /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
00069     return ERR_ARG;
00070   }
00071 
00072   PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
00073   tlv->type_len = 1;
00074 
00075   /* write length */
00076   if (tlv->value_len <= 127) {
00077     length_bytes_required = 1;
00078   } else if (tlv->value_len <= 255) {
00079     length_bytes_required = 2;
00080   } else  {
00081     length_bytes_required = 3;
00082   }
00083 
00084   /* check for forced min length */
00085   if (tlv->length_len > 0) {
00086     if (tlv->length_len < length_bytes_required) {
00087       /* unable to code requested length in requested number of bytes */
00088       return ERR_ARG;
00089     }
00090 
00091     length_bytes_required = tlv->length_len;
00092   } else {
00093     tlv->length_len = length_bytes_required;
00094   }
00095 
00096   if (length_bytes_required > 1) {
00097     /* multi byte representation required */
00098     length_bytes_required--;
00099     data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
00100 
00101     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
00102 
00103     while (length_bytes_required > 1) {
00104       if (length_bytes_required == 2) {
00105         /* append high byte */
00106         data = (u8_t)(tlv->value_len >> 8);
00107       } else {
00108         /* append leading 0x00 */
00109         data = 0x00;
00110       }
00111 
00112       PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
00113       length_bytes_required--;
00114     }
00115   }
00116 
00117   /* append low byte */
00118   data = (u8_t)(tlv->value_len & 0xFF);
00119   PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
00120 
00121   return ERR_OK;
00122 }
00123 
00124 /**
00125  * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
00126  *
00127  * @param pbuf_stream points to a pbuf stream
00128  * @param raw_len raw data length
00129  * @param raw points raw data
00130  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
00131  */
00132 err_t
00133 snmp_asn1_enc_raw(struct snmp_pbuf_stream *pbuf_stream, const u8_t *raw, u16_t raw_len)
00134 {
00135   PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
00136 
00137   return ERR_OK;
00138 }
00139 
00140 /**
00141  * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
00142  *
00143  * @param pbuf_stream points to a pbuf stream
00144  * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
00145  * @param value is the host order u32_t value to be encoded
00146  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
00147  *
00148  * @see snmp_asn1_enc_u32t_cnt()
00149  */
00150 err_t
00151 snmp_asn1_enc_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u32_t value)
00152 {
00153   if (octets_needed > 5) {
00154     return ERR_ARG;
00155   }
00156   if (octets_needed == 5) {
00157     /* not enough bits in 'value' add leading 0x00 */
00158     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
00159     octets_needed--;
00160   }
00161 
00162   while (octets_needed > 1) {
00163     octets_needed--;
00164     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
00165   }
00166 
00167   /* (only) one least significant octet */
00168   PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
00169 
00170   return ERR_OK;
00171 }
00172 /**
00173  * Encodes s32_t integer into a pbuf chained ASN1 msg.
00174  *
00175  * @param pbuf_stream points to a pbuf stream
00176  * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
00177  * @param value is the host order s32_t value to be encoded
00178  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
00179  *
00180  * @see snmp_asn1_enc_s32t_cnt()
00181  */
00182 err_t
00183 snmp_asn1_enc_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, s32_t value)
00184 {
00185   while (octets_needed > 1) {
00186     octets_needed--;
00187 
00188     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
00189   }
00190 
00191   /* (only) one least significant octet */
00192   PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
00193 
00194   return ERR_OK;
00195 }
00196 
00197 /**
00198  * Encodes object identifier into a pbuf chained ASN1 msg.
00199  *
00200  * @param pbuf_stream points to a pbuf stream
00201  * @param oid points to object identifier array
00202  * @param oid_len object identifier array length
00203  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
00204  */
00205 err_t
00206 snmp_asn1_enc_oid(struct snmp_pbuf_stream *pbuf_stream, const u32_t *oid, u16_t oid_len)
00207 {
00208   if (oid_len > 1) {
00209     /* write compressed first two sub id's */
00210     u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
00211     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
00212     oid_len -= 2;
00213     oid += 2;
00214   } else {
00215     /* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
00216     /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
00217     return ERR_ARG;
00218   }
00219 
00220   while (oid_len > 0) {
00221     u32_t sub_id;
00222     u8_t shift, tail;
00223 
00224     oid_len--;
00225     sub_id = *oid;
00226     tail = 0;
00227     shift = 28;
00228     while (shift > 0) {
00229       u8_t code;
00230 
00231       code = (u8_t)(sub_id >> shift);
00232       if ((code != 0) || (tail != 0)) {
00233         tail = 1;
00234         PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
00235       }
00236       shift -= 7;
00237     }
00238     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
00239 
00240     /* proceed to next sub-identifier */
00241     oid++;
00242   }
00243   return ERR_OK;
00244 }
00245 
00246 /**
00247  * Returns octet count for length.
00248  *
00249  * @param length parameter length
00250  * @param octets_needed points to the return value
00251  */
00252 void
00253 snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
00254 {
00255   if (length < 0x80U) {
00256     *octets_needed = 1;
00257   } else if (length < 0x100U) {
00258     *octets_needed = 2;
00259   } else {
00260     *octets_needed = 3;
00261   }
00262 }
00263 
00264 /**
00265  * Returns octet count for an u32_t.
00266  *
00267  * @param value value to be encoded
00268  * @param octets_needed points to the return value
00269  *
00270  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
00271  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
00272  * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
00273  */
00274 void
00275 snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
00276 {
00277   if (value < 0x80UL) {
00278     *octets_needed = 1;
00279   } else if (value < 0x8000UL) {
00280     *octets_needed = 2;
00281   } else if (value < 0x800000UL) {
00282     *octets_needed = 3;
00283   } else if (value < 0x80000000UL) {
00284     *octets_needed = 4;
00285   } else {
00286     *octets_needed = 5;
00287   }
00288 }
00289 
00290 /**
00291  * Returns octet count for an s32_t.
00292  *
00293  * @param value value to be encoded
00294  * @param octets_needed points to the return value
00295  *
00296  * @note ASN coded integers are _always_ signed.
00297  */
00298 void
00299 snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
00300 {
00301   if (value < 0) {
00302     value = ~value;
00303   }
00304   if (value < 0x80L) {
00305     *octets_needed = 1;
00306   } else if (value < 0x8000L) {
00307     *octets_needed = 2;
00308   } else if (value < 0x800000L) {
00309     *octets_needed = 3;
00310   } else {
00311     *octets_needed = 4;
00312   }
00313 }
00314 
00315 /**
00316  * Returns octet count for an object identifier.
00317  *
00318  * @param oid points to object identifier array
00319  * @param oid_len object identifier array length
00320  * @param octets_needed points to the return value
00321  */
00322 void
00323 snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
00324 {
00325   u32_t sub_id;
00326 
00327   *octets_needed = 0;
00328   if (oid_len > 1) {
00329     /* compressed prefix in one octet */
00330     (*octets_needed)++;
00331     oid_len -= 2;
00332     oid += 2;
00333   }
00334   while (oid_len > 0) {
00335     oid_len--;
00336     sub_id = *oid;
00337 
00338     sub_id >>= 7;
00339     (*octets_needed)++;
00340     while (sub_id > 0) {
00341       sub_id >>= 7;
00342       (*octets_needed)++;
00343     }
00344     oid++;
00345   }
00346 }
00347 
00348 /**
00349  * Decodes a TLV from a pbuf stream.
00350  *
00351  * @param pbuf_stream points to a pbuf stream
00352  * @param tlv returns decoded TLV
00353  * @return ERR_OK if successful, ERR_VAL if we can't decode
00354  */
00355 err_t
00356 snmp_asn1_dec_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv)
00357 {
00358   u8_t data;
00359 
00360   /* decode type first */
00361   PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00362   tlv->type = data;
00363 
00364   if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
00365     /* extended format is not used by SNMP so we do not accept those values */
00366     return ERR_VAL;
00367   }
00368   tlv->type_len = 1;
00369 
00370   /* now, decode length */
00371   PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00372 
00373   if (data < 0x80) { /* short form */
00374     tlv->length_len = 1;
00375     tlv->value_len  = data;
00376   } else if (data > 0x80) { /* long form */
00377     u8_t length_bytes = data - 0x80;
00378     if (length_bytes > pbuf_stream->length) {
00379       return ERR_VAL;
00380     }
00381     tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
00382     tlv->value_len = 0;
00383 
00384     while (length_bytes > 0) {
00385       /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
00386       if (tlv->value_len > 0xFF) {
00387         return ERR_VAL;
00388       }
00389       PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00390       tlv->value_len <<= 8;
00391       tlv->value_len |= data;
00392 
00393       /* take care for special value used for indefinite length */
00394       if (tlv->value_len == 0xFFFF) {
00395         return ERR_VAL;
00396       }
00397 
00398       length_bytes--;
00399     }
00400   } else { /* data == 0x80 indefinite length form */
00401     /* (not allowed for SNMP; RFC 1157, 3.2.2) */
00402     return ERR_VAL;
00403   }
00404 
00405   return ERR_OK;
00406 }
00407 
00408 /**
00409  * Decodes positive integer (counter, gauge, timeticks) into u32_t.
00410  *
00411  * @param pbuf_stream points to a pbuf stream
00412  * @param len length of the coded integer field
00413  * @param value return host order integer
00414  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
00415  *
00416  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
00417  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
00418  * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
00419  */
00420 err_t
00421 snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
00422 {
00423   u8_t data;
00424 
00425   if ((len > 0) && (len <= 5)) {
00426     PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00427 
00428     /* expecting sign bit to be zero, only unsigned please! */
00429     if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
00430       *value = data;
00431       len--;
00432 
00433       while (len > 0) {
00434         PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00435         len--;
00436 
00437         *value <<= 8;
00438         *value |= data;
00439       }
00440 
00441       return ERR_OK;
00442     }
00443   }
00444 
00445   return ERR_VAL;
00446 }
00447 
00448 /**
00449  * Decodes integer into s32_t.
00450  *
00451  * @param pbuf_stream points to a pbuf stream
00452  * @param len length of the coded integer field
00453  * @param value return host order integer
00454  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
00455  *
00456  * @note ASN coded integers are _always_ signed!
00457  */
00458 err_t
00459 snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
00460 {
00461   u8_t data;
00462 
00463   if ((len > 0) && (len < 5)) {
00464     PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00465 
00466     if (data & 0x80) {
00467       /* negative, start from -1 */
00468       *value = -1;
00469       *value = (*value << 8) | data;
00470     } else {
00471       /* positive, start from 0 */
00472       *value = data;
00473     }
00474     len--;
00475     /* shift in the remaining value */
00476     while (len > 0) {
00477       PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00478       *value = (*value << 8) | data;
00479       len--;
00480     }
00481     return ERR_OK;
00482   }
00483 
00484   return ERR_VAL;
00485 }
00486 
00487 /**
00488  * Decodes object identifier from incoming message into array of u32_t.
00489  *
00490  * @param pbuf_stream points to a pbuf stream
00491  * @param len length of the coded object identifier
00492  * @param oid return decoded object identifier
00493  * @param oid_len return decoded object identifier length
00494  * @param oid_max_len size of oid buffer
00495  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
00496  */
00497 err_t
00498 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)
00499 {
00500   u32_t *oid_ptr;
00501   u8_t data;
00502 
00503   *oid_len = 0;
00504   oid_ptr = oid;
00505   if (len > 0) {
00506     if (oid_max_len < 2) {
00507       return ERR_MEM;
00508     }
00509 
00510     PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00511     len--;
00512 
00513     /* first compressed octet */
00514     if (data == 0x2B) {
00515       /* (most) common case 1.3 (iso.org) */
00516       *oid_ptr = 1;
00517       oid_ptr++;
00518       *oid_ptr = 3;
00519       oid_ptr++;
00520     } else if (data < 40) {
00521       *oid_ptr = 0;
00522       oid_ptr++;
00523       *oid_ptr = data;
00524       oid_ptr++;
00525     } else if (data < 80) {
00526       *oid_ptr = 1;
00527       oid_ptr++;
00528       *oid_ptr = data - 40;
00529       oid_ptr++;
00530     } else {
00531       *oid_ptr = 2;
00532       oid_ptr++;
00533       *oid_ptr = data - 80;
00534       oid_ptr++;
00535     }
00536     *oid_len = 2;
00537   } else {
00538     /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
00539     return ERR_OK;
00540   }
00541 
00542   while ((len > 0) && (*oid_len < oid_max_len)) {
00543     PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00544     len--;
00545 
00546     if ((data & 0x80) == 0x00) {
00547       /* sub-identifier uses single octet */
00548       *oid_ptr = data;
00549     } else {
00550       /* sub-identifier uses multiple octets */
00551       u32_t sub_id = (data & ~0x80);
00552       while ((len > 0) && ((data & 0x80) != 0)) {
00553         PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00554         len--;
00555 
00556         sub_id = (sub_id << 7) + (data & ~0x80);
00557       }
00558 
00559       if ((data & 0x80) != 0) {
00560         /* "more bytes following" bit still set at end of len */
00561         return ERR_VAL;
00562       }
00563       *oid_ptr = sub_id;
00564     }
00565     oid_ptr++;
00566     (*oid_len)++;
00567   }
00568 
00569   if (len > 0) {
00570     /* OID to long to fit in our buffer */
00571     return ERR_MEM;
00572   }
00573 
00574   return ERR_OK;
00575 }
00576 
00577 /**
00578  * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
00579  * from incoming message into array.
00580  *
00581  * @param pbuf_stream points to a pbuf stream
00582  * @param len length of the coded raw data (zero is valid, e.g. empty string!)
00583  * @param buf return raw bytes
00584  * @param buf_len returns length of the raw return value
00585  * @param buf_max_len buffer size
00586  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
00587  */
00588 err_t
00589 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)
00590 {
00591   if (len > buf_max_len) {
00592     /* not enough dst space */
00593     return ERR_MEM;
00594   }
00595   *buf_len = len;
00596 
00597   while (len > 0) {
00598     PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
00599     buf++;
00600     len--;
00601   }
00602 
00603   return ERR_OK;
00604 }
00605 
00606 #if LWIP_HAVE_INT64
00607 /**
00608  * Returns octet count for an u64_t.
00609  *
00610  * @param value value to be encoded
00611  * @param octets_needed points to the return value
00612  *
00613  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
00614  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
00615  * of 0xFFFFFFFFFFFFFFFF is preceded with 0x00 and the length is 9 octets!!
00616  */
00617 void
00618 snmp_asn1_enc_u64t_cnt(u64_t value, u16_t *octets_needed)
00619 {
00620   /* check if high u32 is 0 */
00621   if ((value >> 32) == 0) {
00622     /* only low u32 is important */
00623     snmp_asn1_enc_u32t_cnt((u32_t)value, octets_needed);
00624   } else {
00625     /* low u32 does not matter for length determination */
00626     snmp_asn1_enc_u32t_cnt((u32_t)(value >> 32), octets_needed);
00627     *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
00628   }
00629 }
00630 
00631 /**
00632  * Decodes large positive integer (counter64) into 2x u32_t.
00633  *
00634  * @param pbuf_stream points to a pbuf stream
00635  * @param len length of the coded integer field
00636  * @param value return 64 bit integer
00637  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
00638  *
00639  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
00640  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
00641  * of 0xFFFFFFFFFFFFFFFF is preceded with 0x00 and the length is 9 octets!!
00642  */
00643 err_t
00644 snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u64_t *value)
00645 {
00646   u8_t data;
00647 
00648   if ((len > 0) && (len <= 9)) {
00649     PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00650 
00651     /* expecting sign bit to be zero, only unsigned please! */
00652     if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
00653       *value = data;
00654       len--;
00655 
00656       while (len > 0) {
00657         PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
00658         *value <<= 8;
00659         *value |= data;
00660         len--;
00661       }
00662 
00663       return ERR_OK;
00664     }
00665   }
00666 
00667   return ERR_VAL;
00668 }
00669 
00670 /**
00671  * Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
00672  *
00673  * @param pbuf_stream points to a pbuf stream
00674  * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
00675  * @param value is the value to be encoded
00676  * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
00677  *
00678  * @see snmp_asn1_enc_u64t_cnt()
00679  */
00680 err_t
00681 snmp_asn1_enc_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u64_t value)
00682 {
00683   if (octets_needed > 9) {
00684     return ERR_ARG;
00685   }
00686   if (octets_needed == 9) {
00687     /* not enough bits in 'value' add leading 0x00 */
00688     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
00689     octets_needed--;
00690   }
00691 
00692   while (octets_needed > 1) {
00693     octets_needed--;
00694     PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
00695   }
00696 
00697   /* always write at least one octet (also in case of value == 0) */
00698   PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value)));
00699 
00700   return ERR_OK;
00701 }
00702 #endif
00703 
00704 #endif /* LWIP_SNMP */