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.
Fork of lwip by
asn1_dec.c
00001 /** 00002 * @file 00003 * Abstract Syntax Notation One (ISO 8824, 8825) decoding 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 */ 00036 00037 #include "lwip/opt.h" 00038 00039 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 00040 00041 #include "lwip/snmp_asn1.h" 00042 00043 /** 00044 * Retrieves type field from incoming pbuf chain. 00045 * 00046 * @param p points to a pbuf holding an ASN1 coded type field 00047 * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field 00048 * @param type return ASN1 type 00049 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode 00050 */ 00051 err_t 00052 snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type) 00053 { 00054 u16_t plen, base; 00055 u8_t *msg_ptr; 00056 00057 plen = 0; 00058 while (p != NULL) 00059 { 00060 base = plen; 00061 plen += p->len; 00062 if (ofs < plen) 00063 { 00064 msg_ptr = (u8_t*)p->payload; 00065 msg_ptr += ofs - base; 00066 *type = *msg_ptr; 00067 return ERR_OK; 00068 } 00069 p = p->next; 00070 } 00071 /* p == NULL, ofs >= plen */ 00072 return ERR_ARG; 00073 } 00074 00075 /** 00076 * Decodes length field from incoming pbuf chain into host length. 00077 * 00078 * @param p points to a pbuf holding an ASN1 coded length 00079 * @param ofs points to the offset within the pbuf chain of the ASN1 coded length 00080 * @param octets_used returns number of octets used by the length code 00081 * @param length return host order length, upto 64k 00082 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode 00083 */ 00084 err_t 00085 snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length) 00086 { 00087 u16_t plen, base; 00088 u8_t *msg_ptr; 00089 00090 plen = 0; 00091 while (p != NULL) 00092 { 00093 base = plen; 00094 plen += p->len; 00095 if (ofs < plen) 00096 { 00097 msg_ptr = (u8_t*)p->payload; 00098 msg_ptr += ofs - base; 00099 00100 if (*msg_ptr < 0x80) 00101 { 00102 /* primitive definite length format */ 00103 *octets_used = 1; 00104 *length = *msg_ptr; 00105 return ERR_OK; 00106 } 00107 else if (*msg_ptr == 0x80) 00108 { 00109 /* constructed indefinite length format, termination with two zero octets */ 00110 u8_t zeros; 00111 u8_t i; 00112 00113 *length = 0; 00114 zeros = 0; 00115 while (zeros != 2) 00116 { 00117 i = 2; 00118 while (i > 0) 00119 { 00120 i--; 00121 (*length) += 1; 00122 ofs += 1; 00123 if (ofs >= plen) 00124 { 00125 /* next octet in next pbuf */ 00126 p = p->next; 00127 if (p == NULL) { return ERR_ARG; } 00128 msg_ptr = (u8_t*)p->payload; 00129 plen += p->len; 00130 } 00131 else 00132 { 00133 /* next octet in same pbuf */ 00134 msg_ptr++; 00135 } 00136 if (*msg_ptr == 0) 00137 { 00138 zeros++; 00139 if (zeros == 2) 00140 { 00141 /* stop while (i > 0) */ 00142 i = 0; 00143 } 00144 } 00145 else 00146 { 00147 zeros = 0; 00148 } 00149 } 00150 } 00151 *octets_used = 1; 00152 return ERR_OK; 00153 } 00154 else if (*msg_ptr == 0x81) 00155 { 00156 /* constructed definite length format, one octet */ 00157 ofs += 1; 00158 if (ofs >= plen) 00159 { 00160 /* next octet in next pbuf */ 00161 p = p->next; 00162 if (p == NULL) { return ERR_ARG; } 00163 msg_ptr = (u8_t*)p->payload; 00164 } 00165 else 00166 { 00167 /* next octet in same pbuf */ 00168 msg_ptr++; 00169 } 00170 *length = *msg_ptr; 00171 *octets_used = 2; 00172 return ERR_OK; 00173 } 00174 else if (*msg_ptr == 0x82) 00175 { 00176 u8_t i; 00177 00178 /* constructed definite length format, two octets */ 00179 i = 2; 00180 while (i > 0) 00181 { 00182 i--; 00183 ofs += 1; 00184 if (ofs >= plen) 00185 { 00186 /* next octet in next pbuf */ 00187 p = p->next; 00188 if (p == NULL) { return ERR_ARG; } 00189 msg_ptr = (u8_t*)p->payload; 00190 plen += p->len; 00191 } 00192 else 00193 { 00194 /* next octet in same pbuf */ 00195 msg_ptr++; 00196 } 00197 if (i == 0) 00198 { 00199 /* least significant length octet */ 00200 *length |= *msg_ptr; 00201 } 00202 else 00203 { 00204 /* most significant length octet */ 00205 *length = (*msg_ptr) << 8; 00206 } 00207 } 00208 *octets_used = 3; 00209 return ERR_OK; 00210 } 00211 else 00212 { 00213 /* constructed definite length format 3..127 octets, this is too big (>64k) */ 00214 /** @todo: do we need to accept inefficient codings with many leading zero's? */ 00215 *octets_used = 1 + ((*msg_ptr) & 0x7f); 00216 return ERR_ARG; 00217 } 00218 } 00219 p = p->next; 00220 } 00221 00222 /* p == NULL, ofs >= plen */ 00223 return ERR_ARG; 00224 } 00225 00226 /** 00227 * Decodes positive integer (counter, gauge, timeticks) into u32_t. 00228 * 00229 * @param p points to a pbuf holding an ASN1 coded integer 00230 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer 00231 * @param len length of the coded integer field 00232 * @param value return host order integer 00233 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode 00234 * 00235 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded 00236 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value 00237 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! 00238 */ 00239 err_t 00240 snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) 00241 { 00242 u16_t plen, base; 00243 u8_t *msg_ptr; 00244 00245 plen = 0; 00246 while (p != NULL) 00247 { 00248 base = plen; 00249 plen += p->len; 00250 if (ofs < plen) 00251 { 00252 msg_ptr = (u8_t*)p->payload; 00253 msg_ptr += ofs - base; 00254 if ((len > 0) && (len < 6)) 00255 { 00256 /* start from zero */ 00257 *value = 0; 00258 if (*msg_ptr & 0x80) 00259 { 00260 /* negative, expecting zero sign bit! */ 00261 return ERR_ARG; 00262 } 00263 else 00264 { 00265 /* positive */ 00266 if ((len > 1) && (*msg_ptr == 0)) 00267 { 00268 /* skip leading "sign byte" octet 0x00 */ 00269 len--; 00270 ofs += 1; 00271 if (ofs >= plen) 00272 { 00273 /* next octet in next pbuf */ 00274 p = p->next; 00275 if (p == NULL) { return ERR_ARG; } 00276 msg_ptr = (u8_t*)p->payload; 00277 plen += p->len; 00278 } 00279 else 00280 { 00281 /* next octet in same pbuf */ 00282 msg_ptr++; 00283 } 00284 } 00285 } 00286 /* OR octets with value */ 00287 while (len > 1) 00288 { 00289 len--; 00290 *value |= *msg_ptr; 00291 *value <<= 8; 00292 ofs += 1; 00293 if (ofs >= plen) 00294 { 00295 /* next octet in next pbuf */ 00296 p = p->next; 00297 if (p == NULL) { return ERR_ARG; } 00298 msg_ptr = (u8_t*)p->payload; 00299 plen += p->len; 00300 } 00301 else 00302 { 00303 /* next octet in same pbuf */ 00304 msg_ptr++; 00305 } 00306 } 00307 *value |= *msg_ptr; 00308 return ERR_OK; 00309 } 00310 else 00311 { 00312 return ERR_ARG; 00313 } 00314 } 00315 p = p->next; 00316 } 00317 /* p == NULL, ofs >= plen */ 00318 return ERR_ARG; 00319 } 00320 00321 /** 00322 * Decodes integer into s32_t. 00323 * 00324 * @param p points to a pbuf holding an ASN1 coded integer 00325 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer 00326 * @param len length of the coded integer field 00327 * @param value return host order integer 00328 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode 00329 * 00330 * @note ASN coded integers are _always_ signed! 00331 */ 00332 err_t 00333 snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) 00334 { 00335 u16_t plen, base; 00336 u8_t *msg_ptr; 00337 #if BYTE_ORDER == LITTLE_ENDIAN 00338 u8_t *lsb_ptr = (u8_t*)value; 00339 #endif 00340 #if BYTE_ORDER == BIG_ENDIAN 00341 u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; 00342 #endif 00343 u8_t sign; 00344 00345 plen = 0; 00346 while (p != NULL) 00347 { 00348 base = plen; 00349 plen += p->len; 00350 if (ofs < plen) 00351 { 00352 msg_ptr = (u8_t*)p->payload; 00353 msg_ptr += ofs - base; 00354 if ((len > 0) && (len < 5)) 00355 { 00356 if (*msg_ptr & 0x80) 00357 { 00358 /* negative, start from -1 */ 00359 *value = -1; 00360 sign = 1; 00361 } 00362 else 00363 { 00364 /* positive, start from 0 */ 00365 *value = 0; 00366 sign = 0; 00367 } 00368 /* OR/AND octets with value */ 00369 while (len > 1) 00370 { 00371 len--; 00372 if (sign) 00373 { 00374 *lsb_ptr &= *msg_ptr; 00375 *value <<= 8; 00376 *lsb_ptr |= 255; 00377 } 00378 else 00379 { 00380 *lsb_ptr |= *msg_ptr; 00381 *value <<= 8; 00382 } 00383 ofs += 1; 00384 if (ofs >= plen) 00385 { 00386 /* next octet in next pbuf */ 00387 p = p->next; 00388 if (p == NULL) { return ERR_ARG; } 00389 msg_ptr = (u8_t*)p->payload; 00390 plen += p->len; 00391 } 00392 else 00393 { 00394 /* next octet in same pbuf */ 00395 msg_ptr++; 00396 } 00397 } 00398 if (sign) 00399 { 00400 *lsb_ptr &= *msg_ptr; 00401 } 00402 else 00403 { 00404 *lsb_ptr |= *msg_ptr; 00405 } 00406 return ERR_OK; 00407 } 00408 else 00409 { 00410 return ERR_ARG; 00411 } 00412 } 00413 p = p->next; 00414 } 00415 /* p == NULL, ofs >= plen */ 00416 return ERR_ARG; 00417 } 00418 00419 /** 00420 * Decodes object identifier from incoming message into array of s32_t. 00421 * 00422 * @param p points to a pbuf holding an ASN1 coded object identifier 00423 * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier 00424 * @param len length of the coded object identifier 00425 * @param oid return object identifier struct 00426 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode 00427 */ 00428 err_t 00429 snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) 00430 { 00431 u16_t plen, base; 00432 u8_t *msg_ptr; 00433 s32_t *oid_ptr; 00434 00435 plen = 0; 00436 while (p != NULL) 00437 { 00438 base = plen; 00439 plen += p->len; 00440 if (ofs < plen) 00441 { 00442 msg_ptr = (u8_t*)p->payload; 00443 msg_ptr += ofs - base; 00444 00445 oid->len = 0; 00446 oid_ptr = &oid->id[0]; 00447 if (len > 0) 00448 { 00449 /* first compressed octet */ 00450 if (*msg_ptr == 0x2B) 00451 { 00452 /* (most) common case 1.3 (iso.org) */ 00453 *oid_ptr = 1; 00454 oid_ptr++; 00455 *oid_ptr = 3; 00456 oid_ptr++; 00457 } 00458 else if (*msg_ptr < 40) 00459 { 00460 *oid_ptr = 0; 00461 oid_ptr++; 00462 *oid_ptr = *msg_ptr; 00463 oid_ptr++; 00464 } 00465 else if (*msg_ptr < 80) 00466 { 00467 *oid_ptr = 1; 00468 oid_ptr++; 00469 *oid_ptr = (*msg_ptr) - 40; 00470 oid_ptr++; 00471 } 00472 else 00473 { 00474 *oid_ptr = 2; 00475 oid_ptr++; 00476 *oid_ptr = (*msg_ptr) - 80; 00477 oid_ptr++; 00478 } 00479 oid->len = 2; 00480 } 00481 else 00482 { 00483 /* accepting zero length identifiers e.g. for 00484 getnext operation. uncommon but valid */ 00485 return ERR_OK; 00486 } 00487 len--; 00488 if (len > 0) 00489 { 00490 ofs += 1; 00491 if (ofs >= plen) 00492 { 00493 /* next octet in next pbuf */ 00494 p = p->next; 00495 if (p == NULL) { return ERR_ARG; } 00496 msg_ptr = (u8_t*)p->payload; 00497 plen += p->len; 00498 } 00499 else 00500 { 00501 /* next octet in same pbuf */ 00502 msg_ptr++; 00503 } 00504 } 00505 while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN)) 00506 { 00507 /* sub-identifier uses multiple octets */ 00508 if (*msg_ptr & 0x80) 00509 { 00510 s32_t sub_id = 0; 00511 00512 while ((*msg_ptr & 0x80) && (len > 1)) 00513 { 00514 len--; 00515 sub_id = (sub_id << 7) + (*msg_ptr & ~0x80); 00516 ofs += 1; 00517 if (ofs >= plen) 00518 { 00519 /* next octet in next pbuf */ 00520 p = p->next; 00521 if (p == NULL) { return ERR_ARG; } 00522 msg_ptr = (u8_t*)p->payload; 00523 plen += p->len; 00524 } 00525 else 00526 { 00527 /* next octet in same pbuf */ 00528 msg_ptr++; 00529 } 00530 } 00531 if (!(*msg_ptr & 0x80) && (len > 0)) 00532 { 00533 /* last octet sub-identifier */ 00534 len--; 00535 sub_id = (sub_id << 7) + *msg_ptr; 00536 *oid_ptr = sub_id; 00537 } 00538 } 00539 else 00540 { 00541 /* !(*msg_ptr & 0x80) sub-identifier uses single octet */ 00542 len--; 00543 *oid_ptr = *msg_ptr; 00544 } 00545 if (len > 0) 00546 { 00547 /* remaining oid bytes available ... */ 00548 ofs += 1; 00549 if (ofs >= plen) 00550 { 00551 /* next octet in next pbuf */ 00552 p = p->next; 00553 if (p == NULL) { return ERR_ARG; } 00554 msg_ptr = (u8_t*)p->payload; 00555 plen += p->len; 00556 } 00557 else 00558 { 00559 /* next octet in same pbuf */ 00560 msg_ptr++; 00561 } 00562 } 00563 oid_ptr++; 00564 oid->len++; 00565 } 00566 if (len == 0) 00567 { 00568 /* len == 0, end of oid */ 00569 return ERR_OK; 00570 } 00571 else 00572 { 00573 /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */ 00574 return ERR_ARG; 00575 } 00576 00577 } 00578 p = p->next; 00579 } 00580 /* p == NULL, ofs >= plen */ 00581 return ERR_ARG; 00582 } 00583 00584 /** 00585 * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) 00586 * from incoming message into array. 00587 * 00588 * @param p points to a pbuf holding an ASN1 coded raw data 00589 * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data 00590 * @param len length of the coded raw data (zero is valid, e.g. empty string!) 00591 * @param raw_len length of the raw return value 00592 * @param raw return raw bytes 00593 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode 00594 */ 00595 err_t 00596 snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw) 00597 { 00598 u16_t plen, base; 00599 u8_t *msg_ptr; 00600 00601 if (len > 0) 00602 { 00603 plen = 0; 00604 while (p != NULL) 00605 { 00606 base = plen; 00607 plen += p->len; 00608 if (ofs < plen) 00609 { 00610 msg_ptr = (u8_t*)p->payload; 00611 msg_ptr += ofs - base; 00612 if (raw_len >= len) 00613 { 00614 while (len > 1) 00615 { 00616 /* copy len - 1 octets */ 00617 len--; 00618 *raw = *msg_ptr; 00619 raw++; 00620 ofs += 1; 00621 if (ofs >= plen) 00622 { 00623 /* next octet in next pbuf */ 00624 p = p->next; 00625 if (p == NULL) { return ERR_ARG; } 00626 msg_ptr = (u8_t*)p->payload; 00627 plen += p->len; 00628 } 00629 else 00630 { 00631 /* next octet in same pbuf */ 00632 msg_ptr++; 00633 } 00634 } 00635 /* copy last octet */ 00636 *raw = *msg_ptr; 00637 return ERR_OK; 00638 } 00639 else 00640 { 00641 /* raw_len < len, not enough dst space */ 00642 return ERR_ARG; 00643 } 00644 } 00645 p = p->next; 00646 } 00647 /* p == NULL, ofs >= plen */ 00648 return ERR_ARG; 00649 } 00650 else 00651 { 00652 /* len == 0, empty string */ 00653 return ERR_OK; 00654 } 00655 } 00656 00657 #endif /* LWIP_SNMP */
Generated on Tue Jul 12 2022 11:29:36 by
