Deprecated fork of old network stack source from github. Please use official library instead: https://mbed.org/users/mbed_official/code/EthernetInterface/
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 23:10:19 by 1.7.2