Ethernetwebsoc

Dependencies:   C12832_lcd LM75B WebSocketClient mbed-rtos mbed Socket lwip-eth lwip-sys lwip

Committer:
GordonSin
Date:
Fri May 31 04:09:54 2013 +0000
Revision:
0:0ed2a7c7190c
31/5/2013;

Who changed what in which revision?

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