Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_snmp_asn1.c
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 */
Generated on Tue Jul 12 2022 13:54:29 by
