This library is stripped down version of NetServices library. HTTP server and client function is NOT supported.

Dependents:   imu-daq-eth

Committer:
idinor
Date:
Wed Jul 20 11:45:39 2011 +0000
Revision:
0:dcf3c92487ca

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
idinor 0:dcf3c92487ca 1 /**
idinor 0:dcf3c92487ca 2 * @file
idinor 0:dcf3c92487ca 3 * Abstract Syntax Notation One (ISO 8824, 8825) decoding
idinor 0:dcf3c92487ca 4 *
idinor 0:dcf3c92487ca 5 * @todo not optimised (yet), favor correctness over speed, favor speed over size
idinor 0:dcf3c92487ca 6 */
idinor 0:dcf3c92487ca 7
idinor 0:dcf3c92487ca 8 /*
idinor 0:dcf3c92487ca 9 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
idinor 0:dcf3c92487ca 10 * All rights reserved.
idinor 0:dcf3c92487ca 11 *
idinor 0:dcf3c92487ca 12 * Redistribution and use in source and binary forms, with or without modification,
idinor 0:dcf3c92487ca 13 * are permitted provided that the following conditions are met:
idinor 0:dcf3c92487ca 14 *
idinor 0:dcf3c92487ca 15 * 1. Redistributions of source code must retain the above copyright notice,
idinor 0:dcf3c92487ca 16 * this list of conditions and the following disclaimer.
idinor 0:dcf3c92487ca 17 * 2. Redistributions in binary form must reproduce the above copyright notice,
idinor 0:dcf3c92487ca 18 * this list of conditions and the following disclaimer in the documentation
idinor 0:dcf3c92487ca 19 * and/or other materials provided with the distribution.
idinor 0:dcf3c92487ca 20 * 3. The name of the author may not be used to endorse or promote products
idinor 0:dcf3c92487ca 21 * derived from this software without specific prior written permission.
idinor 0:dcf3c92487ca 22 *
idinor 0:dcf3c92487ca 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
idinor 0:dcf3c92487ca 24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
idinor 0:dcf3c92487ca 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
idinor 0:dcf3c92487ca 26 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
idinor 0:dcf3c92487ca 27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
idinor 0:dcf3c92487ca 28 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
idinor 0:dcf3c92487ca 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
idinor 0:dcf3c92487ca 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
idinor 0:dcf3c92487ca 31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
idinor 0:dcf3c92487ca 32 * OF SUCH DAMAGE.
idinor 0:dcf3c92487ca 33 *
idinor 0:dcf3c92487ca 34 * Author: Christiaan Simons <christiaan.simons@axon.tv>
idinor 0:dcf3c92487ca 35 */
idinor 0:dcf3c92487ca 36
idinor 0:dcf3c92487ca 37 #include "lwip/opt.h"
idinor 0:dcf3c92487ca 38
idinor 0:dcf3c92487ca 39 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
idinor 0:dcf3c92487ca 40
idinor 0:dcf3c92487ca 41 #include "lwip/snmp_asn1.h"
idinor 0:dcf3c92487ca 42
idinor 0:dcf3c92487ca 43 /**
idinor 0:dcf3c92487ca 44 * Retrieves type field from incoming pbuf chain.
idinor 0:dcf3c92487ca 45 *
idinor 0:dcf3c92487ca 46 * @param p points to a pbuf holding an ASN1 coded type field
idinor 0:dcf3c92487ca 47 * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
idinor 0:dcf3c92487ca 48 * @param type return ASN1 type
idinor 0:dcf3c92487ca 49 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
idinor 0:dcf3c92487ca 50 */
idinor 0:dcf3c92487ca 51 err_t
idinor 0:dcf3c92487ca 52 snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
idinor 0:dcf3c92487ca 53 {
idinor 0:dcf3c92487ca 54 u16_t plen, base;
idinor 0:dcf3c92487ca 55 u8_t *msg_ptr;
idinor 0:dcf3c92487ca 56
idinor 0:dcf3c92487ca 57 plen = 0;
idinor 0:dcf3c92487ca 58 while (p != NULL)
idinor 0:dcf3c92487ca 59 {
idinor 0:dcf3c92487ca 60 base = plen;
idinor 0:dcf3c92487ca 61 plen += p->len;
idinor 0:dcf3c92487ca 62 if (ofs < plen)
idinor 0:dcf3c92487ca 63 {
idinor 0:dcf3c92487ca 64 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 65 msg_ptr += ofs - base;
idinor 0:dcf3c92487ca 66 *type = *msg_ptr;
idinor 0:dcf3c92487ca 67 return ERR_OK;
idinor 0:dcf3c92487ca 68 }
idinor 0:dcf3c92487ca 69 p = p->next;
idinor 0:dcf3c92487ca 70 }
idinor 0:dcf3c92487ca 71 /* p == NULL, ofs >= plen */
idinor 0:dcf3c92487ca 72 return ERR_ARG;
idinor 0:dcf3c92487ca 73 }
idinor 0:dcf3c92487ca 74
idinor 0:dcf3c92487ca 75 /**
idinor 0:dcf3c92487ca 76 * Decodes length field from incoming pbuf chain into host length.
idinor 0:dcf3c92487ca 77 *
idinor 0:dcf3c92487ca 78 * @param p points to a pbuf holding an ASN1 coded length
idinor 0:dcf3c92487ca 79 * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
idinor 0:dcf3c92487ca 80 * @param octets_used returns number of octets used by the length code
idinor 0:dcf3c92487ca 81 * @param length return host order length, upto 64k
idinor 0:dcf3c92487ca 82 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
idinor 0:dcf3c92487ca 83 */
idinor 0:dcf3c92487ca 84 err_t
idinor 0:dcf3c92487ca 85 snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
idinor 0:dcf3c92487ca 86 {
idinor 0:dcf3c92487ca 87 u16_t plen, base;
idinor 0:dcf3c92487ca 88 u8_t *msg_ptr;
idinor 0:dcf3c92487ca 89
idinor 0:dcf3c92487ca 90 plen = 0;
idinor 0:dcf3c92487ca 91 while (p != NULL)
idinor 0:dcf3c92487ca 92 {
idinor 0:dcf3c92487ca 93 base = plen;
idinor 0:dcf3c92487ca 94 plen += p->len;
idinor 0:dcf3c92487ca 95 if (ofs < plen)
idinor 0:dcf3c92487ca 96 {
idinor 0:dcf3c92487ca 97 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 98 msg_ptr += ofs - base;
idinor 0:dcf3c92487ca 99
idinor 0:dcf3c92487ca 100 if (*msg_ptr < 0x80)
idinor 0:dcf3c92487ca 101 {
idinor 0:dcf3c92487ca 102 /* primitive definite length format */
idinor 0:dcf3c92487ca 103 *octets_used = 1;
idinor 0:dcf3c92487ca 104 *length = *msg_ptr;
idinor 0:dcf3c92487ca 105 return ERR_OK;
idinor 0:dcf3c92487ca 106 }
idinor 0:dcf3c92487ca 107 else if (*msg_ptr == 0x80)
idinor 0:dcf3c92487ca 108 {
idinor 0:dcf3c92487ca 109 /* constructed indefinite length format, termination with two zero octets */
idinor 0:dcf3c92487ca 110 u8_t zeros;
idinor 0:dcf3c92487ca 111 u8_t i;
idinor 0:dcf3c92487ca 112
idinor 0:dcf3c92487ca 113 *length = 0;
idinor 0:dcf3c92487ca 114 zeros = 0;
idinor 0:dcf3c92487ca 115 while (zeros != 2)
idinor 0:dcf3c92487ca 116 {
idinor 0:dcf3c92487ca 117 i = 2;
idinor 0:dcf3c92487ca 118 while (i > 0)
idinor 0:dcf3c92487ca 119 {
idinor 0:dcf3c92487ca 120 i--;
idinor 0:dcf3c92487ca 121 (*length) += 1;
idinor 0:dcf3c92487ca 122 ofs += 1;
idinor 0:dcf3c92487ca 123 if (ofs >= plen)
idinor 0:dcf3c92487ca 124 {
idinor 0:dcf3c92487ca 125 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 126 p = p->next;
idinor 0:dcf3c92487ca 127 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 128 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 129 plen += p->len;
idinor 0:dcf3c92487ca 130 }
idinor 0:dcf3c92487ca 131 else
idinor 0:dcf3c92487ca 132 {
idinor 0:dcf3c92487ca 133 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 134 msg_ptr++;
idinor 0:dcf3c92487ca 135 }
idinor 0:dcf3c92487ca 136 if (*msg_ptr == 0)
idinor 0:dcf3c92487ca 137 {
idinor 0:dcf3c92487ca 138 zeros++;
idinor 0:dcf3c92487ca 139 if (zeros == 2)
idinor 0:dcf3c92487ca 140 {
idinor 0:dcf3c92487ca 141 /* stop while (i > 0) */
idinor 0:dcf3c92487ca 142 i = 0;
idinor 0:dcf3c92487ca 143 }
idinor 0:dcf3c92487ca 144 }
idinor 0:dcf3c92487ca 145 else
idinor 0:dcf3c92487ca 146 {
idinor 0:dcf3c92487ca 147 zeros = 0;
idinor 0:dcf3c92487ca 148 }
idinor 0:dcf3c92487ca 149 }
idinor 0:dcf3c92487ca 150 }
idinor 0:dcf3c92487ca 151 *octets_used = 1;
idinor 0:dcf3c92487ca 152 return ERR_OK;
idinor 0:dcf3c92487ca 153 }
idinor 0:dcf3c92487ca 154 else if (*msg_ptr == 0x81)
idinor 0:dcf3c92487ca 155 {
idinor 0:dcf3c92487ca 156 /* constructed definite length format, one octet */
idinor 0:dcf3c92487ca 157 ofs += 1;
idinor 0:dcf3c92487ca 158 if (ofs >= plen)
idinor 0:dcf3c92487ca 159 {
idinor 0:dcf3c92487ca 160 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 161 p = p->next;
idinor 0:dcf3c92487ca 162 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 163 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 164 }
idinor 0:dcf3c92487ca 165 else
idinor 0:dcf3c92487ca 166 {
idinor 0:dcf3c92487ca 167 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 168 msg_ptr++;
idinor 0:dcf3c92487ca 169 }
idinor 0:dcf3c92487ca 170 *length = *msg_ptr;
idinor 0:dcf3c92487ca 171 *octets_used = 2;
idinor 0:dcf3c92487ca 172 return ERR_OK;
idinor 0:dcf3c92487ca 173 }
idinor 0:dcf3c92487ca 174 else if (*msg_ptr == 0x82)
idinor 0:dcf3c92487ca 175 {
idinor 0:dcf3c92487ca 176 u8_t i;
idinor 0:dcf3c92487ca 177
idinor 0:dcf3c92487ca 178 /* constructed definite length format, two octets */
idinor 0:dcf3c92487ca 179 i = 2;
idinor 0:dcf3c92487ca 180 while (i > 0)
idinor 0:dcf3c92487ca 181 {
idinor 0:dcf3c92487ca 182 i--;
idinor 0:dcf3c92487ca 183 ofs += 1;
idinor 0:dcf3c92487ca 184 if (ofs >= plen)
idinor 0:dcf3c92487ca 185 {
idinor 0:dcf3c92487ca 186 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 187 p = p->next;
idinor 0:dcf3c92487ca 188 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 189 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 190 plen += p->len;
idinor 0:dcf3c92487ca 191 }
idinor 0:dcf3c92487ca 192 else
idinor 0:dcf3c92487ca 193 {
idinor 0:dcf3c92487ca 194 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 195 msg_ptr++;
idinor 0:dcf3c92487ca 196 }
idinor 0:dcf3c92487ca 197 if (i == 0)
idinor 0:dcf3c92487ca 198 {
idinor 0:dcf3c92487ca 199 /* least significant length octet */
idinor 0:dcf3c92487ca 200 *length |= *msg_ptr;
idinor 0:dcf3c92487ca 201 }
idinor 0:dcf3c92487ca 202 else
idinor 0:dcf3c92487ca 203 {
idinor 0:dcf3c92487ca 204 /* most significant length octet */
idinor 0:dcf3c92487ca 205 *length = (*msg_ptr) << 8;
idinor 0:dcf3c92487ca 206 }
idinor 0:dcf3c92487ca 207 }
idinor 0:dcf3c92487ca 208 *octets_used = 3;
idinor 0:dcf3c92487ca 209 return ERR_OK;
idinor 0:dcf3c92487ca 210 }
idinor 0:dcf3c92487ca 211 else
idinor 0:dcf3c92487ca 212 {
idinor 0:dcf3c92487ca 213 /* constructed definite length format 3..127 octets, this is too big (>64k) */
idinor 0:dcf3c92487ca 214 /** @todo: do we need to accept inefficient codings with many leading zero's? */
idinor 0:dcf3c92487ca 215 *octets_used = 1 + ((*msg_ptr) & 0x7f);
idinor 0:dcf3c92487ca 216 return ERR_ARG;
idinor 0:dcf3c92487ca 217 }
idinor 0:dcf3c92487ca 218 }
idinor 0:dcf3c92487ca 219 p = p->next;
idinor 0:dcf3c92487ca 220 }
idinor 0:dcf3c92487ca 221
idinor 0:dcf3c92487ca 222 /* p == NULL, ofs >= plen */
idinor 0:dcf3c92487ca 223 return ERR_ARG;
idinor 0:dcf3c92487ca 224 }
idinor 0:dcf3c92487ca 225
idinor 0:dcf3c92487ca 226 /**
idinor 0:dcf3c92487ca 227 * Decodes positive integer (counter, gauge, timeticks) into u32_t.
idinor 0:dcf3c92487ca 228 *
idinor 0:dcf3c92487ca 229 * @param p points to a pbuf holding an ASN1 coded integer
idinor 0:dcf3c92487ca 230 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
idinor 0:dcf3c92487ca 231 * @param len length of the coded integer field
idinor 0:dcf3c92487ca 232 * @param value return host order integer
idinor 0:dcf3c92487ca 233 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
idinor 0:dcf3c92487ca 234 *
idinor 0:dcf3c92487ca 235 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
idinor 0:dcf3c92487ca 236 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
idinor 0:dcf3c92487ca 237 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
idinor 0:dcf3c92487ca 238 */
idinor 0:dcf3c92487ca 239 err_t
idinor 0:dcf3c92487ca 240 snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
idinor 0:dcf3c92487ca 241 {
idinor 0:dcf3c92487ca 242 u16_t plen, base;
idinor 0:dcf3c92487ca 243 u8_t *msg_ptr;
idinor 0:dcf3c92487ca 244
idinor 0:dcf3c92487ca 245 plen = 0;
idinor 0:dcf3c92487ca 246 while (p != NULL)
idinor 0:dcf3c92487ca 247 {
idinor 0:dcf3c92487ca 248 base = plen;
idinor 0:dcf3c92487ca 249 plen += p->len;
idinor 0:dcf3c92487ca 250 if (ofs < plen)
idinor 0:dcf3c92487ca 251 {
idinor 0:dcf3c92487ca 252 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 253 msg_ptr += ofs - base;
idinor 0:dcf3c92487ca 254 if ((len > 0) && (len < 6))
idinor 0:dcf3c92487ca 255 {
idinor 0:dcf3c92487ca 256 /* start from zero */
idinor 0:dcf3c92487ca 257 *value = 0;
idinor 0:dcf3c92487ca 258 if (*msg_ptr & 0x80)
idinor 0:dcf3c92487ca 259 {
idinor 0:dcf3c92487ca 260 /* negative, expecting zero sign bit! */
idinor 0:dcf3c92487ca 261 return ERR_ARG;
idinor 0:dcf3c92487ca 262 }
idinor 0:dcf3c92487ca 263 else
idinor 0:dcf3c92487ca 264 {
idinor 0:dcf3c92487ca 265 /* positive */
idinor 0:dcf3c92487ca 266 if ((len > 1) && (*msg_ptr == 0))
idinor 0:dcf3c92487ca 267 {
idinor 0:dcf3c92487ca 268 /* skip leading "sign byte" octet 0x00 */
idinor 0:dcf3c92487ca 269 len--;
idinor 0:dcf3c92487ca 270 ofs += 1;
idinor 0:dcf3c92487ca 271 if (ofs >= plen)
idinor 0:dcf3c92487ca 272 {
idinor 0:dcf3c92487ca 273 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 274 p = p->next;
idinor 0:dcf3c92487ca 275 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 276 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 277 plen += p->len;
idinor 0:dcf3c92487ca 278 }
idinor 0:dcf3c92487ca 279 else
idinor 0:dcf3c92487ca 280 {
idinor 0:dcf3c92487ca 281 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 282 msg_ptr++;
idinor 0:dcf3c92487ca 283 }
idinor 0:dcf3c92487ca 284 }
idinor 0:dcf3c92487ca 285 }
idinor 0:dcf3c92487ca 286 /* OR octets with value */
idinor 0:dcf3c92487ca 287 while (len > 1)
idinor 0:dcf3c92487ca 288 {
idinor 0:dcf3c92487ca 289 len--;
idinor 0:dcf3c92487ca 290 *value |= *msg_ptr;
idinor 0:dcf3c92487ca 291 *value <<= 8;
idinor 0:dcf3c92487ca 292 ofs += 1;
idinor 0:dcf3c92487ca 293 if (ofs >= plen)
idinor 0:dcf3c92487ca 294 {
idinor 0:dcf3c92487ca 295 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 296 p = p->next;
idinor 0:dcf3c92487ca 297 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 298 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 299 plen += p->len;
idinor 0:dcf3c92487ca 300 }
idinor 0:dcf3c92487ca 301 else
idinor 0:dcf3c92487ca 302 {
idinor 0:dcf3c92487ca 303 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 304 msg_ptr++;
idinor 0:dcf3c92487ca 305 }
idinor 0:dcf3c92487ca 306 }
idinor 0:dcf3c92487ca 307 *value |= *msg_ptr;
idinor 0:dcf3c92487ca 308 return ERR_OK;
idinor 0:dcf3c92487ca 309 }
idinor 0:dcf3c92487ca 310 else
idinor 0:dcf3c92487ca 311 {
idinor 0:dcf3c92487ca 312 return ERR_ARG;
idinor 0:dcf3c92487ca 313 }
idinor 0:dcf3c92487ca 314 }
idinor 0:dcf3c92487ca 315 p = p->next;
idinor 0:dcf3c92487ca 316 }
idinor 0:dcf3c92487ca 317 /* p == NULL, ofs >= plen */
idinor 0:dcf3c92487ca 318 return ERR_ARG;
idinor 0:dcf3c92487ca 319 }
idinor 0:dcf3c92487ca 320
idinor 0:dcf3c92487ca 321 /**
idinor 0:dcf3c92487ca 322 * Decodes integer into s32_t.
idinor 0:dcf3c92487ca 323 *
idinor 0:dcf3c92487ca 324 * @param p points to a pbuf holding an ASN1 coded integer
idinor 0:dcf3c92487ca 325 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
idinor 0:dcf3c92487ca 326 * @param len length of the coded integer field
idinor 0:dcf3c92487ca 327 * @param value return host order integer
idinor 0:dcf3c92487ca 328 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
idinor 0:dcf3c92487ca 329 *
idinor 0:dcf3c92487ca 330 * @note ASN coded integers are _always_ signed!
idinor 0:dcf3c92487ca 331 */
idinor 0:dcf3c92487ca 332 err_t
idinor 0:dcf3c92487ca 333 snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
idinor 0:dcf3c92487ca 334 {
idinor 0:dcf3c92487ca 335 u16_t plen, base;
idinor 0:dcf3c92487ca 336 u8_t *msg_ptr;
idinor 0:dcf3c92487ca 337 #if BYTE_ORDER == LITTLE_ENDIAN
idinor 0:dcf3c92487ca 338 u8_t *lsb_ptr = (u8_t*)value;
idinor 0:dcf3c92487ca 339 #endif
idinor 0:dcf3c92487ca 340 #if BYTE_ORDER == BIG_ENDIAN
idinor 0:dcf3c92487ca 341 u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
idinor 0:dcf3c92487ca 342 #endif
idinor 0:dcf3c92487ca 343 u8_t sign;
idinor 0:dcf3c92487ca 344
idinor 0:dcf3c92487ca 345 plen = 0;
idinor 0:dcf3c92487ca 346 while (p != NULL)
idinor 0:dcf3c92487ca 347 {
idinor 0:dcf3c92487ca 348 base = plen;
idinor 0:dcf3c92487ca 349 plen += p->len;
idinor 0:dcf3c92487ca 350 if (ofs < plen)
idinor 0:dcf3c92487ca 351 {
idinor 0:dcf3c92487ca 352 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 353 msg_ptr += ofs - base;
idinor 0:dcf3c92487ca 354 if ((len > 0) && (len < 5))
idinor 0:dcf3c92487ca 355 {
idinor 0:dcf3c92487ca 356 if (*msg_ptr & 0x80)
idinor 0:dcf3c92487ca 357 {
idinor 0:dcf3c92487ca 358 /* negative, start from -1 */
idinor 0:dcf3c92487ca 359 *value = -1;
idinor 0:dcf3c92487ca 360 sign = 1;
idinor 0:dcf3c92487ca 361 }
idinor 0:dcf3c92487ca 362 else
idinor 0:dcf3c92487ca 363 {
idinor 0:dcf3c92487ca 364 /* positive, start from 0 */
idinor 0:dcf3c92487ca 365 *value = 0;
idinor 0:dcf3c92487ca 366 sign = 0;
idinor 0:dcf3c92487ca 367 }
idinor 0:dcf3c92487ca 368 /* OR/AND octets with value */
idinor 0:dcf3c92487ca 369 while (len > 1)
idinor 0:dcf3c92487ca 370 {
idinor 0:dcf3c92487ca 371 len--;
idinor 0:dcf3c92487ca 372 if (sign)
idinor 0:dcf3c92487ca 373 {
idinor 0:dcf3c92487ca 374 *lsb_ptr &= *msg_ptr;
idinor 0:dcf3c92487ca 375 *value <<= 8;
idinor 0:dcf3c92487ca 376 *lsb_ptr |= 255;
idinor 0:dcf3c92487ca 377 }
idinor 0:dcf3c92487ca 378 else
idinor 0:dcf3c92487ca 379 {
idinor 0:dcf3c92487ca 380 *lsb_ptr |= *msg_ptr;
idinor 0:dcf3c92487ca 381 *value <<= 8;
idinor 0:dcf3c92487ca 382 }
idinor 0:dcf3c92487ca 383 ofs += 1;
idinor 0:dcf3c92487ca 384 if (ofs >= plen)
idinor 0:dcf3c92487ca 385 {
idinor 0:dcf3c92487ca 386 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 387 p = p->next;
idinor 0:dcf3c92487ca 388 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 389 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 390 plen += p->len;
idinor 0:dcf3c92487ca 391 }
idinor 0:dcf3c92487ca 392 else
idinor 0:dcf3c92487ca 393 {
idinor 0:dcf3c92487ca 394 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 395 msg_ptr++;
idinor 0:dcf3c92487ca 396 }
idinor 0:dcf3c92487ca 397 }
idinor 0:dcf3c92487ca 398 if (sign)
idinor 0:dcf3c92487ca 399 {
idinor 0:dcf3c92487ca 400 *lsb_ptr &= *msg_ptr;
idinor 0:dcf3c92487ca 401 }
idinor 0:dcf3c92487ca 402 else
idinor 0:dcf3c92487ca 403 {
idinor 0:dcf3c92487ca 404 *lsb_ptr |= *msg_ptr;
idinor 0:dcf3c92487ca 405 }
idinor 0:dcf3c92487ca 406 return ERR_OK;
idinor 0:dcf3c92487ca 407 }
idinor 0:dcf3c92487ca 408 else
idinor 0:dcf3c92487ca 409 {
idinor 0:dcf3c92487ca 410 return ERR_ARG;
idinor 0:dcf3c92487ca 411 }
idinor 0:dcf3c92487ca 412 }
idinor 0:dcf3c92487ca 413 p = p->next;
idinor 0:dcf3c92487ca 414 }
idinor 0:dcf3c92487ca 415 /* p == NULL, ofs >= plen */
idinor 0:dcf3c92487ca 416 return ERR_ARG;
idinor 0:dcf3c92487ca 417 }
idinor 0:dcf3c92487ca 418
idinor 0:dcf3c92487ca 419 /**
idinor 0:dcf3c92487ca 420 * Decodes object identifier from incoming message into array of s32_t.
idinor 0:dcf3c92487ca 421 *
idinor 0:dcf3c92487ca 422 * @param p points to a pbuf holding an ASN1 coded object identifier
idinor 0:dcf3c92487ca 423 * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
idinor 0:dcf3c92487ca 424 * @param len length of the coded object identifier
idinor 0:dcf3c92487ca 425 * @param oid return object identifier struct
idinor 0:dcf3c92487ca 426 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
idinor 0:dcf3c92487ca 427 */
idinor 0:dcf3c92487ca 428 err_t
idinor 0:dcf3c92487ca 429 snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
idinor 0:dcf3c92487ca 430 {
idinor 0:dcf3c92487ca 431 u16_t plen, base;
idinor 0:dcf3c92487ca 432 u8_t *msg_ptr;
idinor 0:dcf3c92487ca 433 s32_t *oid_ptr;
idinor 0:dcf3c92487ca 434
idinor 0:dcf3c92487ca 435 plen = 0;
idinor 0:dcf3c92487ca 436 while (p != NULL)
idinor 0:dcf3c92487ca 437 {
idinor 0:dcf3c92487ca 438 base = plen;
idinor 0:dcf3c92487ca 439 plen += p->len;
idinor 0:dcf3c92487ca 440 if (ofs < plen)
idinor 0:dcf3c92487ca 441 {
idinor 0:dcf3c92487ca 442 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 443 msg_ptr += ofs - base;
idinor 0:dcf3c92487ca 444
idinor 0:dcf3c92487ca 445 oid->len = 0;
idinor 0:dcf3c92487ca 446 oid_ptr = &oid->id[0];
idinor 0:dcf3c92487ca 447 if (len > 0)
idinor 0:dcf3c92487ca 448 {
idinor 0:dcf3c92487ca 449 /* first compressed octet */
idinor 0:dcf3c92487ca 450 if (*msg_ptr == 0x2B)
idinor 0:dcf3c92487ca 451 {
idinor 0:dcf3c92487ca 452 /* (most) common case 1.3 (iso.org) */
idinor 0:dcf3c92487ca 453 *oid_ptr = 1;
idinor 0:dcf3c92487ca 454 oid_ptr++;
idinor 0:dcf3c92487ca 455 *oid_ptr = 3;
idinor 0:dcf3c92487ca 456 oid_ptr++;
idinor 0:dcf3c92487ca 457 }
idinor 0:dcf3c92487ca 458 else if (*msg_ptr < 40)
idinor 0:dcf3c92487ca 459 {
idinor 0:dcf3c92487ca 460 *oid_ptr = 0;
idinor 0:dcf3c92487ca 461 oid_ptr++;
idinor 0:dcf3c92487ca 462 *oid_ptr = *msg_ptr;
idinor 0:dcf3c92487ca 463 oid_ptr++;
idinor 0:dcf3c92487ca 464 }
idinor 0:dcf3c92487ca 465 else if (*msg_ptr < 80)
idinor 0:dcf3c92487ca 466 {
idinor 0:dcf3c92487ca 467 *oid_ptr = 1;
idinor 0:dcf3c92487ca 468 oid_ptr++;
idinor 0:dcf3c92487ca 469 *oid_ptr = (*msg_ptr) - 40;
idinor 0:dcf3c92487ca 470 oid_ptr++;
idinor 0:dcf3c92487ca 471 }
idinor 0:dcf3c92487ca 472 else
idinor 0:dcf3c92487ca 473 {
idinor 0:dcf3c92487ca 474 *oid_ptr = 2;
idinor 0:dcf3c92487ca 475 oid_ptr++;
idinor 0:dcf3c92487ca 476 *oid_ptr = (*msg_ptr) - 80;
idinor 0:dcf3c92487ca 477 oid_ptr++;
idinor 0:dcf3c92487ca 478 }
idinor 0:dcf3c92487ca 479 oid->len = 2;
idinor 0:dcf3c92487ca 480 }
idinor 0:dcf3c92487ca 481 else
idinor 0:dcf3c92487ca 482 {
idinor 0:dcf3c92487ca 483 /* accepting zero length identifiers e.g. for
idinor 0:dcf3c92487ca 484 getnext operation. uncommon but valid */
idinor 0:dcf3c92487ca 485 return ERR_OK;
idinor 0:dcf3c92487ca 486 }
idinor 0:dcf3c92487ca 487 len--;
idinor 0:dcf3c92487ca 488 if (len > 0)
idinor 0:dcf3c92487ca 489 {
idinor 0:dcf3c92487ca 490 ofs += 1;
idinor 0:dcf3c92487ca 491 if (ofs >= plen)
idinor 0:dcf3c92487ca 492 {
idinor 0:dcf3c92487ca 493 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 494 p = p->next;
idinor 0:dcf3c92487ca 495 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 496 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 497 plen += p->len;
idinor 0:dcf3c92487ca 498 }
idinor 0:dcf3c92487ca 499 else
idinor 0:dcf3c92487ca 500 {
idinor 0:dcf3c92487ca 501 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 502 msg_ptr++;
idinor 0:dcf3c92487ca 503 }
idinor 0:dcf3c92487ca 504 }
idinor 0:dcf3c92487ca 505 while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
idinor 0:dcf3c92487ca 506 {
idinor 0:dcf3c92487ca 507 /* sub-identifier uses multiple octets */
idinor 0:dcf3c92487ca 508 if (*msg_ptr & 0x80)
idinor 0:dcf3c92487ca 509 {
idinor 0:dcf3c92487ca 510 s32_t sub_id = 0;
idinor 0:dcf3c92487ca 511
idinor 0:dcf3c92487ca 512 while ((*msg_ptr & 0x80) && (len > 1))
idinor 0:dcf3c92487ca 513 {
idinor 0:dcf3c92487ca 514 len--;
idinor 0:dcf3c92487ca 515 sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
idinor 0:dcf3c92487ca 516 ofs += 1;
idinor 0:dcf3c92487ca 517 if (ofs >= plen)
idinor 0:dcf3c92487ca 518 {
idinor 0:dcf3c92487ca 519 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 520 p = p->next;
idinor 0:dcf3c92487ca 521 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 522 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 523 plen += p->len;
idinor 0:dcf3c92487ca 524 }
idinor 0:dcf3c92487ca 525 else
idinor 0:dcf3c92487ca 526 {
idinor 0:dcf3c92487ca 527 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 528 msg_ptr++;
idinor 0:dcf3c92487ca 529 }
idinor 0:dcf3c92487ca 530 }
idinor 0:dcf3c92487ca 531 if (!(*msg_ptr & 0x80) && (len > 0))
idinor 0:dcf3c92487ca 532 {
idinor 0:dcf3c92487ca 533 /* last octet sub-identifier */
idinor 0:dcf3c92487ca 534 len--;
idinor 0:dcf3c92487ca 535 sub_id = (sub_id << 7) + *msg_ptr;
idinor 0:dcf3c92487ca 536 *oid_ptr = sub_id;
idinor 0:dcf3c92487ca 537 }
idinor 0:dcf3c92487ca 538 }
idinor 0:dcf3c92487ca 539 else
idinor 0:dcf3c92487ca 540 {
idinor 0:dcf3c92487ca 541 /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
idinor 0:dcf3c92487ca 542 len--;
idinor 0:dcf3c92487ca 543 *oid_ptr = *msg_ptr;
idinor 0:dcf3c92487ca 544 }
idinor 0:dcf3c92487ca 545 if (len > 0)
idinor 0:dcf3c92487ca 546 {
idinor 0:dcf3c92487ca 547 /* remaining oid bytes available ... */
idinor 0:dcf3c92487ca 548 ofs += 1;
idinor 0:dcf3c92487ca 549 if (ofs >= plen)
idinor 0:dcf3c92487ca 550 {
idinor 0:dcf3c92487ca 551 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 552 p = p->next;
idinor 0:dcf3c92487ca 553 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 554 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 555 plen += p->len;
idinor 0:dcf3c92487ca 556 }
idinor 0:dcf3c92487ca 557 else
idinor 0:dcf3c92487ca 558 {
idinor 0:dcf3c92487ca 559 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 560 msg_ptr++;
idinor 0:dcf3c92487ca 561 }
idinor 0:dcf3c92487ca 562 }
idinor 0:dcf3c92487ca 563 oid_ptr++;
idinor 0:dcf3c92487ca 564 oid->len++;
idinor 0:dcf3c92487ca 565 }
idinor 0:dcf3c92487ca 566 if (len == 0)
idinor 0:dcf3c92487ca 567 {
idinor 0:dcf3c92487ca 568 /* len == 0, end of oid */
idinor 0:dcf3c92487ca 569 return ERR_OK;
idinor 0:dcf3c92487ca 570 }
idinor 0:dcf3c92487ca 571 else
idinor 0:dcf3c92487ca 572 {
idinor 0:dcf3c92487ca 573 /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
idinor 0:dcf3c92487ca 574 return ERR_ARG;
idinor 0:dcf3c92487ca 575 }
idinor 0:dcf3c92487ca 576
idinor 0:dcf3c92487ca 577 }
idinor 0:dcf3c92487ca 578 p = p->next;
idinor 0:dcf3c92487ca 579 }
idinor 0:dcf3c92487ca 580 /* p == NULL, ofs >= plen */
idinor 0:dcf3c92487ca 581 return ERR_ARG;
idinor 0:dcf3c92487ca 582 }
idinor 0:dcf3c92487ca 583
idinor 0:dcf3c92487ca 584 /**
idinor 0:dcf3c92487ca 585 * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
idinor 0:dcf3c92487ca 586 * from incoming message into array.
idinor 0:dcf3c92487ca 587 *
idinor 0:dcf3c92487ca 588 * @param p points to a pbuf holding an ASN1 coded raw data
idinor 0:dcf3c92487ca 589 * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
idinor 0:dcf3c92487ca 590 * @param len length of the coded raw data (zero is valid, e.g. empty string!)
idinor 0:dcf3c92487ca 591 * @param raw_len length of the raw return value
idinor 0:dcf3c92487ca 592 * @param raw return raw bytes
idinor 0:dcf3c92487ca 593 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
idinor 0:dcf3c92487ca 594 */
idinor 0:dcf3c92487ca 595 err_t
idinor 0:dcf3c92487ca 596 snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
idinor 0:dcf3c92487ca 597 {
idinor 0:dcf3c92487ca 598 u16_t plen, base;
idinor 0:dcf3c92487ca 599 u8_t *msg_ptr;
idinor 0:dcf3c92487ca 600
idinor 0:dcf3c92487ca 601 if (len > 0)
idinor 0:dcf3c92487ca 602 {
idinor 0:dcf3c92487ca 603 plen = 0;
idinor 0:dcf3c92487ca 604 while (p != NULL)
idinor 0:dcf3c92487ca 605 {
idinor 0:dcf3c92487ca 606 base = plen;
idinor 0:dcf3c92487ca 607 plen += p->len;
idinor 0:dcf3c92487ca 608 if (ofs < plen)
idinor 0:dcf3c92487ca 609 {
idinor 0:dcf3c92487ca 610 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 611 msg_ptr += ofs - base;
idinor 0:dcf3c92487ca 612 if (raw_len >= len)
idinor 0:dcf3c92487ca 613 {
idinor 0:dcf3c92487ca 614 while (len > 1)
idinor 0:dcf3c92487ca 615 {
idinor 0:dcf3c92487ca 616 /* copy len - 1 octets */
idinor 0:dcf3c92487ca 617 len--;
idinor 0:dcf3c92487ca 618 *raw = *msg_ptr;
idinor 0:dcf3c92487ca 619 raw++;
idinor 0:dcf3c92487ca 620 ofs += 1;
idinor 0:dcf3c92487ca 621 if (ofs >= plen)
idinor 0:dcf3c92487ca 622 {
idinor 0:dcf3c92487ca 623 /* next octet in next pbuf */
idinor 0:dcf3c92487ca 624 p = p->next;
idinor 0:dcf3c92487ca 625 if (p == NULL) { return ERR_ARG; }
idinor 0:dcf3c92487ca 626 msg_ptr = (u8_t*)p->payload;
idinor 0:dcf3c92487ca 627 plen += p->len;
idinor 0:dcf3c92487ca 628 }
idinor 0:dcf3c92487ca 629 else
idinor 0:dcf3c92487ca 630 {
idinor 0:dcf3c92487ca 631 /* next octet in same pbuf */
idinor 0:dcf3c92487ca 632 msg_ptr++;
idinor 0:dcf3c92487ca 633 }
idinor 0:dcf3c92487ca 634 }
idinor 0:dcf3c92487ca 635 /* copy last octet */
idinor 0:dcf3c92487ca 636 *raw = *msg_ptr;
idinor 0:dcf3c92487ca 637 return ERR_OK;
idinor 0:dcf3c92487ca 638 }
idinor 0:dcf3c92487ca 639 else
idinor 0:dcf3c92487ca 640 {
idinor 0:dcf3c92487ca 641 /* raw_len < len, not enough dst space */
idinor 0:dcf3c92487ca 642 return ERR_ARG;
idinor 0:dcf3c92487ca 643 }
idinor 0:dcf3c92487ca 644 }
idinor 0:dcf3c92487ca 645 p = p->next;
idinor 0:dcf3c92487ca 646 }
idinor 0:dcf3c92487ca 647 /* p == NULL, ofs >= plen */
idinor 0:dcf3c92487ca 648 return ERR_ARG;
idinor 0:dcf3c92487ca 649 }
idinor 0:dcf3c92487ca 650 else
idinor 0:dcf3c92487ca 651 {
idinor 0:dcf3c92487ca 652 /* len == 0, empty string */
idinor 0:dcf3c92487ca 653 return ERR_OK;
idinor 0:dcf3c92487ca 654 }
idinor 0:dcf3c92487ca 655 }
idinor 0:dcf3c92487ca 656
idinor 0:dcf3c92487ca 657 #endif /* LWIP_SNMP */