NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
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:52:56 by 1.7.2