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_enc.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 */ 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 * Returns octet count for length. 00045 * 00046 * @param length 00047 * @param octets_needed points to the return value 00048 */ 00049 void 00050 snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) 00051 { 00052 if (length < 0x80U) 00053 { 00054 *octets_needed = 1; 00055 } 00056 else if (length < 0x100U) 00057 { 00058 *octets_needed = 2; 00059 } 00060 else 00061 { 00062 *octets_needed = 3; 00063 } 00064 } 00065 00066 /** 00067 * Returns octet count for an u32_t. 00068 * 00069 * @param value 00070 * @param octets_needed points to the return value 00071 * 00072 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded 00073 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value 00074 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! 00075 */ 00076 void 00077 snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) 00078 { 00079 if (value < 0x80UL) 00080 { 00081 *octets_needed = 1; 00082 } 00083 else if (value < 0x8000UL) 00084 { 00085 *octets_needed = 2; 00086 } 00087 else if (value < 0x800000UL) 00088 { 00089 *octets_needed = 3; 00090 } 00091 else if (value < 0x80000000UL) 00092 { 00093 *octets_needed = 4; 00094 } 00095 else 00096 { 00097 *octets_needed = 5; 00098 } 00099 } 00100 00101 /** 00102 * Returns octet count for an s32_t. 00103 * 00104 * @param value 00105 * @param octets_needed points to the return value 00106 * 00107 * @note ASN coded integers are _always_ signed. 00108 */ 00109 void 00110 snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) 00111 { 00112 if (value < 0) 00113 { 00114 value = ~value; 00115 } 00116 if (value < 0x80L) 00117 { 00118 *octets_needed = 1; 00119 } 00120 else if (value < 0x8000L) 00121 { 00122 *octets_needed = 2; 00123 } 00124 else if (value < 0x800000L) 00125 { 00126 *octets_needed = 3; 00127 } 00128 else 00129 { 00130 *octets_needed = 4; 00131 } 00132 } 00133 00134 /** 00135 * Returns octet count for an object identifier. 00136 * 00137 * @param ident_len object identifier array length 00138 * @param ident points to object identifier array 00139 * @param octets_needed points to the return value 00140 */ 00141 void 00142 snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed) 00143 { 00144 s32_t sub_id; 00145 u8_t cnt; 00146 00147 cnt = 0; 00148 if (ident_len > 1) 00149 { 00150 /* compressed prefix in one octet */ 00151 cnt++; 00152 ident_len -= 2; 00153 ident += 2; 00154 } 00155 while(ident_len > 0) 00156 { 00157 ident_len--; 00158 sub_id = *ident; 00159 00160 sub_id >>= 7; 00161 cnt++; 00162 while(sub_id > 0) 00163 { 00164 sub_id >>= 7; 00165 cnt++; 00166 } 00167 ident++; 00168 } 00169 *octets_needed = cnt; 00170 } 00171 00172 /** 00173 * Encodes ASN type field into a pbuf chained ASN1 msg. 00174 * 00175 * @param p points to output pbuf to encode value into 00176 * @param ofs points to the offset within the pbuf chain 00177 * @param type input ASN1 type 00178 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode 00179 */ 00180 err_t 00181 snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type) 00182 { 00183 u16_t plen, base; 00184 u8_t *msg_ptr; 00185 00186 plen = 0; 00187 while (p != NULL) 00188 { 00189 base = plen; 00190 plen += p->len; 00191 if (ofs < plen) 00192 { 00193 msg_ptr = (u8_t*)p->payload; 00194 msg_ptr += ofs - base; 00195 *msg_ptr = type; 00196 return ERR_OK; 00197 } 00198 p = p->next; 00199 } 00200 /* p == NULL, ofs >= plen */ 00201 return ERR_ARG; 00202 } 00203 00204 /** 00205 * Encodes host order length field into a pbuf chained ASN1 msg. 00206 * 00207 * @param p points to output pbuf to encode length into 00208 * @param ofs points to the offset within the pbuf chain 00209 * @param length is the host order length to be encoded 00210 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode 00211 */ 00212 err_t 00213 snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) 00214 { 00215 u16_t plen, base; 00216 u8_t *msg_ptr; 00217 00218 plen = 0; 00219 while (p != NULL) 00220 { 00221 base = plen; 00222 plen += p->len; 00223 if (ofs < plen) 00224 { 00225 msg_ptr = (u8_t*)p->payload; 00226 msg_ptr += ofs - base; 00227 00228 if (length < 0x80) 00229 { 00230 *msg_ptr = (u8_t)length; 00231 return ERR_OK; 00232 } 00233 else if (length < 0x100) 00234 { 00235 *msg_ptr = 0x81; 00236 ofs += 1; 00237 if (ofs >= plen) 00238 { 00239 /* next octet in next pbuf */ 00240 p = p->next; 00241 if (p == NULL) { return ERR_ARG; } 00242 msg_ptr = (u8_t*)p->payload; 00243 } 00244 else 00245 { 00246 /* next octet in same pbuf */ 00247 msg_ptr++; 00248 } 00249 *msg_ptr = (u8_t)length; 00250 return ERR_OK; 00251 } 00252 else 00253 { 00254 u8_t i; 00255 00256 /* length >= 0x100 && length <= 0xFFFF */ 00257 *msg_ptr = 0x82; 00258 i = 2; 00259 while (i > 0) 00260 { 00261 i--; 00262 ofs += 1; 00263 if (ofs >= plen) 00264 { 00265 /* next octet in next pbuf */ 00266 p = p->next; 00267 if (p == NULL) { return ERR_ARG; } 00268 msg_ptr = (u8_t*)p->payload; 00269 plen += p->len; 00270 } 00271 else 00272 { 00273 /* next octet in same pbuf */ 00274 msg_ptr++; 00275 } 00276 if (i == 0) 00277 { 00278 /* least significant length octet */ 00279 *msg_ptr = (u8_t)length; 00280 } 00281 else 00282 { 00283 /* most significant length octet */ 00284 *msg_ptr = (u8_t)(length >> 8); 00285 } 00286 } 00287 return ERR_OK; 00288 } 00289 } 00290 p = p->next; 00291 } 00292 /* p == NULL, ofs >= plen */ 00293 return ERR_ARG; 00294 } 00295 00296 /** 00297 * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. 00298 * 00299 * @param p points to output pbuf to encode value into 00300 * @param ofs points to the offset within the pbuf chain 00301 * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) 00302 * @param value is the host order u32_t value to be encoded 00303 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode 00304 * 00305 * @see snmp_asn1_enc_u32t_cnt() 00306 */ 00307 err_t 00308 snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value) 00309 { 00310 u16_t plen, base; 00311 u8_t *msg_ptr; 00312 00313 plen = 0; 00314 while (p != NULL) 00315 { 00316 base = plen; 00317 plen += p->len; 00318 if (ofs < plen) 00319 { 00320 msg_ptr = (u8_t*)p->payload; 00321 msg_ptr += ofs - base; 00322 00323 if (octets_needed == 5) 00324 { 00325 /* not enough bits in 'value' add leading 0x00 */ 00326 octets_needed--; 00327 *msg_ptr = 0x00; 00328 ofs += 1; 00329 if (ofs >= plen) 00330 { 00331 /* next octet in next pbuf */ 00332 p = p->next; 00333 if (p == NULL) { return ERR_ARG; } 00334 msg_ptr = (u8_t*)p->payload; 00335 plen += p->len; 00336 } 00337 else 00338 { 00339 /* next octet in same pbuf */ 00340 msg_ptr++; 00341 } 00342 } 00343 while (octets_needed > 1) 00344 { 00345 octets_needed--; 00346 *msg_ptr = (u8_t)(value >> (octets_needed << 3)); 00347 ofs += 1; 00348 if (ofs >= plen) 00349 { 00350 /* next octet in next pbuf */ 00351 p = p->next; 00352 if (p == NULL) { return ERR_ARG; } 00353 msg_ptr = (u8_t*)p->payload; 00354 plen += p->len; 00355 } 00356 else 00357 { 00358 /* next octet in same pbuf */ 00359 msg_ptr++; 00360 } 00361 } 00362 /* (only) one least significant octet */ 00363 *msg_ptr = (u8_t)value; 00364 return ERR_OK; 00365 } 00366 p = p->next; 00367 } 00368 /* p == NULL, ofs >= plen */ 00369 return ERR_ARG; 00370 } 00371 00372 /** 00373 * Encodes s32_t integer into a pbuf chained ASN1 msg. 00374 * 00375 * @param p points to output pbuf to encode value into 00376 * @param ofs points to the offset within the pbuf chain 00377 * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) 00378 * @param value is the host order s32_t value to be encoded 00379 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode 00380 * 00381 * @see snmp_asn1_enc_s32t_cnt() 00382 */ 00383 err_t 00384 snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value) 00385 { 00386 u16_t plen, base; 00387 u8_t *msg_ptr; 00388 00389 plen = 0; 00390 while (p != NULL) 00391 { 00392 base = plen; 00393 plen += p->len; 00394 if (ofs < plen) 00395 { 00396 msg_ptr = (u8_t*)p->payload; 00397 msg_ptr += ofs - base; 00398 00399 while (octets_needed > 1) 00400 { 00401 octets_needed--; 00402 *msg_ptr = (u8_t)(value >> (octets_needed << 3)); 00403 ofs += 1; 00404 if (ofs >= plen) 00405 { 00406 /* next octet in next pbuf */ 00407 p = p->next; 00408 if (p == NULL) { return ERR_ARG; } 00409 msg_ptr = (u8_t*)p->payload; 00410 plen += p->len; 00411 } 00412 else 00413 { 00414 /* next octet in same pbuf */ 00415 msg_ptr++; 00416 } 00417 } 00418 /* (only) one least significant octet */ 00419 *msg_ptr = (u8_t)value; 00420 return ERR_OK; 00421 } 00422 p = p->next; 00423 } 00424 /* p == NULL, ofs >= plen */ 00425 return ERR_ARG; 00426 } 00427 00428 /** 00429 * Encodes object identifier into a pbuf chained ASN1 msg. 00430 * 00431 * @param p points to output pbuf to encode oid into 00432 * @param ofs points to the offset within the pbuf chain 00433 * @param ident_len object identifier array length 00434 * @param ident points to object identifier array 00435 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode 00436 */ 00437 err_t 00438 snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) 00439 { 00440 u16_t plen, base; 00441 u8_t *msg_ptr; 00442 00443 plen = 0; 00444 while (p != NULL) 00445 { 00446 base = plen; 00447 plen += p->len; 00448 if (ofs < plen) 00449 { 00450 msg_ptr = (u8_t*)p->payload; 00451 msg_ptr += ofs - base; 00452 00453 if (ident_len > 1) 00454 { 00455 if ((ident[0] == 1) && (ident[1] == 3)) 00456 { 00457 /* compressed (most common) prefix .iso.org */ 00458 *msg_ptr = 0x2b; 00459 } 00460 else 00461 { 00462 /* calculate prefix */ 00463 *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]); 00464 } 00465 ofs += 1; 00466 if (ofs >= plen) 00467 { 00468 /* next octet in next pbuf */ 00469 p = p->next; 00470 if (p == NULL) { return ERR_ARG; } 00471 msg_ptr = (u8_t*)p->payload; 00472 plen += p->len; 00473 } 00474 else 00475 { 00476 /* next octet in same pbuf */ 00477 msg_ptr++; 00478 } 00479 ident_len -= 2; 00480 ident += 2; 00481 } 00482 else 00483 { 00484 /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */ 00485 /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ 00486 return ERR_ARG; 00487 } 00488 while (ident_len > 0) 00489 { 00490 s32_t sub_id; 00491 u8_t shift, tail; 00492 00493 ident_len--; 00494 sub_id = *ident; 00495 tail = 0; 00496 shift = 28; 00497 while(shift > 0) 00498 { 00499 u8_t code; 00500 00501 code = (u8_t)(sub_id >> shift); 00502 if ((code != 0) || (tail != 0)) 00503 { 00504 tail = 1; 00505 *msg_ptr = code | 0x80; 00506 ofs += 1; 00507 if (ofs >= plen) 00508 { 00509 /* next octet in next pbuf */ 00510 p = p->next; 00511 if (p == NULL) { return ERR_ARG; } 00512 msg_ptr = (u8_t*)p->payload; 00513 plen += p->len; 00514 } 00515 else 00516 { 00517 /* next octet in same pbuf */ 00518 msg_ptr++; 00519 } 00520 } 00521 shift -= 7; 00522 } 00523 *msg_ptr = (u8_t)sub_id & 0x7F; 00524 if (ident_len > 0) 00525 { 00526 ofs += 1; 00527 if (ofs >= plen) 00528 { 00529 /* next octet in next pbuf */ 00530 p = p->next; 00531 if (p == NULL) { return ERR_ARG; } 00532 msg_ptr = (u8_t*)p->payload; 00533 plen += p->len; 00534 } 00535 else 00536 { 00537 /* next octet in same pbuf */ 00538 msg_ptr++; 00539 } 00540 } 00541 /* proceed to next sub-identifier */ 00542 ident++; 00543 } 00544 return ERR_OK; 00545 } 00546 p = p->next; 00547 } 00548 /* p == NULL, ofs >= plen */ 00549 return ERR_ARG; 00550 } 00551 00552 /** 00553 * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. 00554 * 00555 * @param p points to output pbuf to encode raw data into 00556 * @param ofs points to the offset within the pbuf chain 00557 * @param raw_len raw data length 00558 * @param raw points raw data 00559 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode 00560 */ 00561 err_t 00562 snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw) 00563 { 00564 u16_t plen, base; 00565 u8_t *msg_ptr; 00566 00567 plen = 0; 00568 while (p != NULL) 00569 { 00570 base = plen; 00571 plen += p->len; 00572 if (ofs < plen) 00573 { 00574 msg_ptr = (u8_t*)p->payload; 00575 msg_ptr += ofs - base; 00576 00577 while (raw_len > 1) 00578 { 00579 /* copy raw_len - 1 octets */ 00580 raw_len--; 00581 *msg_ptr = *raw; 00582 raw++; 00583 ofs += 1; 00584 if (ofs >= plen) 00585 { 00586 /* next octet in next pbuf */ 00587 p = p->next; 00588 if (p == NULL) { return ERR_ARG; } 00589 msg_ptr = (u8_t*)p->payload; 00590 plen += p->len; 00591 } 00592 else 00593 { 00594 /* next octet in same pbuf */ 00595 msg_ptr++; 00596 } 00597 } 00598 if (raw_len > 0) 00599 { 00600 /* copy last or single octet */ 00601 *msg_ptr = *raw; 00602 } 00603 return ERR_OK; 00604 } 00605 p = p->next; 00606 } 00607 /* p == NULL, ofs >= plen */ 00608 return ERR_ARG; 00609 } 00610 00611 #endif /* LWIP_SNMP */
Generated on Tue Jul 12 2022 11:29:36 by
