BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * SNMP message processing (RFC1157). |
||
4 | */ |
||
5 | |||
6 | /* |
||
7 | * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. |
||
8 | * Copyright (c) 2016 Elias Oenal. |
||
9 | * All rights reserved. |
||
10 | * |
||
11 | * Redistribution and use in source and binary forms, with or without modification, |
||
12 | * are permitted provided that the following conditions are met: |
||
13 | * |
||
14 | * 1. Redistributions of source code must retain the above copyright notice, |
||
15 | * this list of conditions and the following disclaimer. |
||
16 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
17 | * this list of conditions and the following disclaimer in the documentation |
||
18 | * and/or other materials provided with the distribution. |
||
19 | * 3. The name of the author may not be used to endorse or promote products |
||
20 | * derived from this software without specific prior written permission. |
||
21 | * |
||
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
25 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
26 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
27 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
30 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
31 | * OF SUCH DAMAGE. |
||
32 | * |
||
33 | * Author: Christiaan Simons <christiaan.simons@axon.tv> |
||
34 | * Martin Hentschel <info@cl-soft.de> |
||
35 | * Elias Oenal <lwip@eliasoenal.com> |
||
36 | */ |
||
37 | |||
38 | #include "lwip/apps/snmp_opts.h" |
||
39 | |||
40 | #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ |
||
41 | |||
42 | #include "snmp_msg.h" |
||
43 | #include "snmp_asn1.h" |
||
44 | #include "snmp_core_priv.h" |
||
45 | #include "lwip/ip_addr.h" |
||
46 | #include "lwip/stats.h" |
||
47 | |||
48 | #if LWIP_SNMP_V3 |
||
49 | #include "lwip/apps/snmpv3.h" |
||
50 | #include "snmpv3_priv.h" |
||
51 | #ifdef LWIP_HOOK_FILENAME |
||
52 | #include LWIP_HOOK_FILENAME |
||
53 | #endif |
||
54 | #endif |
||
55 | |||
56 | #include <string.h> |
||
57 | |||
58 | #define SNMP_V3_AUTH_FLAG 0x01 |
||
59 | #define SNMP_V3_PRIV_FLAG 0x02 |
||
60 | |||
61 | /* Security levels */ |
||
62 | #define SNMP_V3_NOAUTHNOPRIV 0x00 |
||
63 | #define SNMP_V3_AUTHNOPRIV SNMP_V3_AUTH_FLAG |
||
64 | #define SNMP_V3_AUTHPRIV (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG) |
||
65 | |||
66 | /* public (non-static) constants */ |
||
67 | /** SNMP community string */ |
||
68 | const char *snmp_community = SNMP_COMMUNITY; |
||
69 | /** SNMP community string for write access */ |
||
70 | const char *snmp_community_write = SNMP_COMMUNITY_WRITE; |
||
71 | /** SNMP community string for sending traps */ |
||
72 | const char *snmp_community_trap = SNMP_COMMUNITY_TRAP; |
||
73 | |||
74 | snmp_write_callback_fct snmp_write_callback = NULL; |
||
75 | void *snmp_write_callback_arg = NULL; |
||
76 | |||
77 | #if LWIP_SNMP_CONFIGURE_VERSIONS |
||
78 | |||
79 | static u8_t v1_enabled = 1; |
||
80 | static u8_t v2c_enabled = 1; |
||
81 | static u8_t v3_enabled = 1; |
||
82 | |||
83 | static u8_t |
||
84 | snmp_version_enabled(u8_t version) |
||
85 | { |
||
86 | LWIP_ASSERT("Invalid SNMP version", (version == SNMP_VERSION_1) || (version == SNMP_VERSION_2c) |
||
87 | #if LWIP_SNMP_V3 |
||
88 | || (version == SNMP_VERSION_3) |
||
89 | #endif |
||
90 | ); |
||
91 | |||
92 | if (version == SNMP_VERSION_1) { |
||
93 | return v1_enabled; |
||
94 | } else if (version == SNMP_VERSION_2c) { |
||
95 | return v2c_enabled; |
||
96 | } |
||
97 | #if LWIP_SNMP_V3 |
||
98 | else { /* version == SNMP_VERSION_3 */ |
||
99 | return v3_enabled; |
||
100 | } |
||
101 | #endif |
||
102 | } |
||
103 | |||
104 | u8_t |
||
105 | snmp_v1_enabled(void) |
||
106 | { |
||
107 | return snmp_version_enabled(SNMP_VERSION_1); |
||
108 | } |
||
109 | |||
110 | u8_t |
||
111 | snmp_v2c_enabled(void) |
||
112 | { |
||
113 | return snmp_version_enabled(SNMP_VERSION_2c); |
||
114 | } |
||
115 | |||
116 | u8_t |
||
117 | snmp_v3_enabled(void) |
||
118 | { |
||
119 | return snmp_version_enabled(SNMP_VERSION_3); |
||
120 | } |
||
121 | |||
122 | static void |
||
123 | snmp_version_enable(u8_t version, u8_t enable) |
||
124 | { |
||
125 | LWIP_ASSERT("Invalid SNMP version", (version == SNMP_VERSION_1) || (version == SNMP_VERSION_2c) |
||
126 | #if LWIP_SNMP_V3 |
||
127 | || (version == SNMP_VERSION_3) |
||
128 | #endif |
||
129 | ); |
||
130 | |||
131 | if (version == SNMP_VERSION_1) { |
||
132 | v1_enabled = enable; |
||
133 | } else if (version == SNMP_VERSION_2c) { |
||
134 | v2c_enabled = enable; |
||
135 | } |
||
136 | #if LWIP_SNMP_V3 |
||
137 | else { /* version == SNMP_VERSION_3 */ |
||
138 | v3_enabled = enable; |
||
139 | } |
||
140 | #endif |
||
141 | } |
||
142 | |||
143 | void |
||
144 | snmp_v1_enable(u8_t enable) |
||
145 | { |
||
146 | snmp_version_enable(SNMP_VERSION_1, enable); |
||
147 | } |
||
148 | |||
149 | void |
||
150 | snmp_v2c_enable(u8_t enable) |
||
151 | { |
||
152 | snmp_version_enable(SNMP_VERSION_2c, enable); |
||
153 | } |
||
154 | |||
155 | void |
||
156 | snmp_v3_enable(u8_t enable) |
||
157 | { |
||
158 | snmp_version_enable(SNMP_VERSION_3, enable); |
||
159 | } |
||
160 | |||
161 | #endif |
||
162 | |||
163 | /** |
||
164 | * @ingroup snmp_core |
||
165 | * Returns current SNMP community string. |
||
166 | * @return current SNMP community string |
||
167 | */ |
||
168 | const char * |
||
169 | snmp_get_community(void) |
||
170 | { |
||
171 | return snmp_community; |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * @ingroup snmp_core |
||
176 | * Sets SNMP community string. |
||
177 | * The string itself (its storage) must be valid throughout the whole life of |
||
178 | * program (or until it is changed to sth else). |
||
179 | * |
||
180 | * @param community is a pointer to new community string |
||
181 | */ |
||
182 | void |
||
183 | snmp_set_community(const char *const community) |
||
184 | { |
||
185 | LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); |
||
186 | snmp_community = community; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * @ingroup snmp_core |
||
191 | * Returns current SNMP write-access community string. |
||
192 | * @return current SNMP write-access community string |
||
193 | */ |
||
194 | const char * |
||
195 | snmp_get_community_write(void) |
||
196 | { |
||
197 | return snmp_community_write; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * @ingroup snmp_traps |
||
202 | * Returns current SNMP community string used for sending traps. |
||
203 | * @return current SNMP community string used for sending traps |
||
204 | */ |
||
205 | const char * |
||
206 | snmp_get_community_trap(void) |
||
207 | { |
||
208 | return snmp_community_trap; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * @ingroup snmp_core |
||
213 | * Sets SNMP community string for write-access. |
||
214 | * The string itself (its storage) must be valid throughout the whole life of |
||
215 | * program (or until it is changed to sth else). |
||
216 | * |
||
217 | * @param community is a pointer to new write-access community string |
||
218 | */ |
||
219 | void |
||
220 | snmp_set_community_write(const char *const community) |
||
221 | { |
||
222 | LWIP_ASSERT("community string must not be NULL", community != NULL); |
||
223 | LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); |
||
224 | snmp_community_write = community; |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * @ingroup snmp_traps |
||
229 | * Sets SNMP community string used for sending traps. |
||
230 | * The string itself (its storage) must be valid throughout the whole life of |
||
231 | * program (or until it is changed to sth else). |
||
232 | * |
||
233 | * @param community is a pointer to new trap community string |
||
234 | */ |
||
235 | void |
||
236 | snmp_set_community_trap(const char *const community) |
||
237 | { |
||
238 | LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); |
||
239 | snmp_community_trap = community; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * @ingroup snmp_core |
||
244 | * Callback fired on every successful write access |
||
245 | */ |
||
246 | void |
||
247 | snmp_set_write_callback(snmp_write_callback_fct write_callback, void *callback_arg) |
||
248 | { |
||
249 | snmp_write_callback = write_callback; |
||
250 | snmp_write_callback_arg = callback_arg; |
||
251 | } |
||
252 | |||
253 | /* ----------------------------------------------------------------------- */ |
||
254 | /* forward declarations */ |
||
255 | /* ----------------------------------------------------------------------- */ |
||
256 | |||
257 | static err_t snmp_process_get_request(struct snmp_request *request); |
||
258 | static err_t snmp_process_getnext_request(struct snmp_request *request); |
||
259 | static err_t snmp_process_getbulk_request(struct snmp_request *request); |
||
260 | static err_t snmp_process_set_request(struct snmp_request *request); |
||
261 | |||
262 | static err_t snmp_parse_inbound_frame(struct snmp_request *request); |
||
263 | static err_t snmp_prepare_outbound_frame(struct snmp_request *request); |
||
264 | static err_t snmp_complete_outbound_frame(struct snmp_request *request); |
||
265 | static void snmp_execute_write_callbacks(struct snmp_request *request); |
||
266 | |||
267 | |||
268 | /* ----------------------------------------------------------------------- */ |
||
269 | /* implementation */ |
||
270 | /* ----------------------------------------------------------------------- */ |
||
271 | |||
272 | void |
||
273 | snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port) |
||
274 | { |
||
275 | err_t err; |
||
276 | struct snmp_request request; |
||
277 | |||
278 | memset(&request, 0, sizeof(request)); |
||
279 | request.handle = handle; |
||
280 | request.source_ip = source_ip; |
||
281 | request.source_port = port; |
||
282 | request.inbound_pbuf = p; |
||
283 | |||
284 | snmp_stats.inpkts++; |
||
285 | |||
286 | err = snmp_parse_inbound_frame(&request); |
||
287 | if (err == ERR_OK) { |
||
288 | err = snmp_prepare_outbound_frame(&request); |
||
289 | if (err == ERR_OK) { |
||
290 | |||
291 | if (request.error_status == SNMP_ERR_NOERROR) { |
||
292 | /* only process frame if we do not already have an error to return (e.g. all readonly) */ |
||
293 | if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) { |
||
294 | err = snmp_process_get_request(&request); |
||
295 | } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) { |
||
296 | err = snmp_process_getnext_request(&request); |
||
297 | } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { |
||
298 | err = snmp_process_getbulk_request(&request); |
||
299 | } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { |
||
300 | err = snmp_process_set_request(&request); |
||
301 | } |
||
302 | } |
||
303 | #if LWIP_SNMP_V3 |
||
304 | else { |
||
305 | struct snmp_varbind vb; |
||
306 | |||
307 | vb.next = NULL; |
||
308 | vb.prev = NULL; |
||
309 | vb.type = SNMP_ASN1_TYPE_COUNTER32; |
||
310 | vb.value_len = sizeof(u32_t); |
||
311 | |||
312 | switch (request.error_status) { |
||
313 | case SNMP_ERR_AUTHORIZATIONERROR: { |
||
314 | static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 }; |
||
315 | snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid)); |
||
316 | vb.value = &snmp_stats.wrongdigests; |
||
317 | } |
||
318 | break; |
||
319 | case SNMP_ERR_UNKNOWN_ENGINEID: { |
||
320 | static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 }; |
||
321 | snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid)); |
||
322 | vb.value = &snmp_stats.unknownengineids; |
||
323 | } |
||
324 | break; |
||
325 | case SNMP_ERR_UNKNOWN_SECURITYNAME: { |
||
326 | static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 }; |
||
327 | snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid)); |
||
328 | vb.value = &snmp_stats.unknownusernames; |
||
329 | } |
||
330 | break; |
||
331 | case SNMP_ERR_UNSUPPORTED_SECLEVEL: { |
||
332 | static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 }; |
||
333 | snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid)); |
||
334 | vb.value = &snmp_stats.unsupportedseclevels; |
||
335 | } |
||
336 | break; |
||
337 | case SNMP_ERR_NOTINTIMEWINDOW: { |
||
338 | static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 }; |
||
339 | snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid)); |
||
340 | vb.value = &snmp_stats.notintimewindows; |
||
341 | } |
||
342 | break; |
||
343 | case SNMP_ERR_DECRYIPTION_ERROR: { |
||
344 | static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 }; |
||
345 | snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid)); |
||
346 | vb.value = &snmp_stats.decryptionerrors; |
||
347 | } |
||
348 | break; |
||
349 | default: |
||
350 | /* Unknown or unhandled error_status */ |
||
351 | err = ERR_ARG; |
||
352 | } |
||
353 | |||
354 | if (err == ERR_OK) { |
||
355 | snmp_append_outbound_varbind(&(request.outbound_pbuf_stream), &vb); |
||
356 | request.error_status = SNMP_ERR_NOERROR; |
||
357 | } |
||
358 | |||
359 | request.request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_REPORT); |
||
360 | request.request_id = request.msg_id; |
||
361 | } |
||
362 | #endif |
||
363 | |||
364 | if (err == ERR_OK) { |
||
365 | err = snmp_complete_outbound_frame(&request); |
||
366 | |||
367 | if (err == ERR_OK) { |
||
368 | err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port); |
||
369 | |||
370 | if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) |
||
371 | && (request.error_status == SNMP_ERR_NOERROR) |
||
372 | && (snmp_write_callback != NULL)) { |
||
373 | /* raise write notification for all written objects */ |
||
374 | snmp_execute_write_callbacks(&request); |
||
375 | } |
||
376 | } |
||
377 | } |
||
378 | } |
||
379 | |||
380 | if (request.outbound_pbuf != NULL) { |
||
381 | pbuf_free(request.outbound_pbuf); |
||
382 | } |
||
383 | } |
||
384 | } |
||
385 | |||
386 | static u8_t |
||
387 | snmp_msg_getnext_validate_node_inst(struct snmp_node_instance *node_instance, void *validate_arg) |
||
388 | { |
||
389 | if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) { |
||
390 | return SNMP_ERR_NOSUCHINSTANCE; |
||
391 | } |
||
392 | |||
393 | #if LWIP_HAVE_INT64 |
||
394 | if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request *)validate_arg)->version == SNMP_VERSION_1)) { |
||
395 | /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */ |
||
396 | return SNMP_ERR_NOSUCHINSTANCE; |
||
397 | } |
||
398 | #endif |
||
399 | |||
400 | return SNMP_ERR_NOERROR; |
||
401 | } |
||
402 | |||
403 | static void |
||
404 | snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next) |
||
405 | { |
||
406 | err_t err; |
||
407 | struct snmp_node_instance node_instance; |
||
408 | memset(&node_instance, 0, sizeof(node_instance)); |
||
409 | |||
410 | if (get_next) { |
||
411 | struct snmp_obj_id result_oid; |
||
412 | request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request, &result_oid, &node_instance); |
||
413 | |||
414 | if (request->error_status == SNMP_ERR_NOERROR) { |
||
415 | snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len); |
||
416 | } |
||
417 | } else { |
||
418 | request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance); |
||
419 | |||
420 | if (request->error_status == SNMP_ERR_NOERROR) { |
||
421 | /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */ |
||
422 | request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request); |
||
423 | |||
424 | if (request->error_status != SNMP_ERR_NOERROR) { |
||
425 | if (node_instance.release_instance != NULL) { |
||
426 | node_instance.release_instance(&node_instance); |
||
427 | } |
||
428 | } |
||
429 | } |
||
430 | } |
||
431 | |||
432 | if (request->error_status != SNMP_ERR_NOERROR) { |
||
433 | if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { |
||
434 | if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) { |
||
435 | /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */ |
||
436 | vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK)); |
||
437 | vb->value_len = 0; |
||
438 | |||
439 | err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb); |
||
440 | if (err == ERR_OK) { |
||
441 | /* we stored the exception in varbind -> go on */ |
||
442 | request->error_status = SNMP_ERR_NOERROR; |
||
443 | } else if (err == ERR_BUF) { |
||
444 | request->error_status = SNMP_ERR_TOOBIG; |
||
445 | } else { |
||
446 | request->error_status = SNMP_ERR_GENERROR; |
||
447 | } |
||
448 | } |
||
449 | } else { |
||
450 | /* according to RFC 1157/1905, all other errors only return genError */ |
||
451 | request->error_status = SNMP_ERR_GENERROR; |
||
452 | } |
||
453 | } else { |
||
454 | s16_t len = node_instance.get_value(&node_instance, vb->value); |
||
455 | vb->type = node_instance.asn1_type; |
||
456 | |||
457 | if (len >= 0) { |
||
458 | vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */ |
||
459 | |||
460 | LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE); |
||
461 | err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb); |
||
462 | |||
463 | if (err == ERR_BUF) { |
||
464 | request->error_status = SNMP_ERR_TOOBIG; |
||
465 | } else if (err != ERR_OK) { |
||
466 | request->error_status = SNMP_ERR_GENERROR; |
||
467 | } |
||
468 | } else { |
||
469 | request->error_status = SNMP_ERR_GENERROR; |
||
470 | } |
||
471 | |||
472 | if (node_instance.release_instance != NULL) { |
||
473 | node_instance.release_instance(&node_instance); |
||
474 | } |
||
475 | } |
||
476 | } |
||
477 | |||
478 | |||
479 | /** |
||
480 | * Service an internal or external event for SNMP GET. |
||
481 | * |
||
482 | * @param request points to the associated message process state |
||
483 | */ |
||
484 | static err_t |
||
485 | snmp_process_get_request(struct snmp_request *request) |
||
486 | { |
||
487 | snmp_vb_enumerator_err_t err; |
||
488 | struct snmp_varbind vb; |
||
489 | vb.value = request->value_buffer; |
||
490 | |||
491 | LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n")); |
||
492 | |||
493 | while (request->error_status == SNMP_ERR_NOERROR) { |
||
494 | err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); |
||
495 | if (err == SNMP_VB_ENUMERATOR_ERR_OK) { |
||
496 | if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { |
||
497 | snmp_process_varbind(request, &vb, 0); |
||
498 | } else { |
||
499 | request->error_status = SNMP_ERR_GENERROR; |
||
500 | } |
||
501 | } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { |
||
502 | /* no more varbinds in request */ |
||
503 | break; |
||
504 | } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { |
||
505 | /* malformed ASN.1, don't answer */ |
||
506 | return ERR_ARG; |
||
507 | } else { |
||
508 | request->error_status = SNMP_ERR_GENERROR; |
||
509 | } |
||
510 | } |
||
511 | |||
512 | return ERR_OK; |
||
513 | } |
||
514 | |||
515 | /** |
||
516 | * Service an internal or external event for SNMP GET. |
||
517 | * |
||
518 | * @param request points to the associated message process state |
||
519 | */ |
||
520 | static err_t |
||
521 | snmp_process_getnext_request(struct snmp_request *request) |
||
522 | { |
||
523 | snmp_vb_enumerator_err_t err; |
||
524 | struct snmp_varbind vb; |
||
525 | vb.value = request->value_buffer; |
||
526 | |||
527 | LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n")); |
||
528 | |||
529 | while (request->error_status == SNMP_ERR_NOERROR) { |
||
530 | err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); |
||
531 | if (err == SNMP_VB_ENUMERATOR_ERR_OK) { |
||
532 | if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { |
||
533 | snmp_process_varbind(request, &vb, 1); |
||
534 | } else { |
||
535 | request->error_status = SNMP_ERR_GENERROR; |
||
536 | } |
||
537 | } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { |
||
538 | /* no more varbinds in request */ |
||
539 | break; |
||
540 | } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { |
||
541 | /* malformed ASN.1, don't answer */ |
||
542 | return ERR_ARG; |
||
543 | } else { |
||
544 | request->error_status = SNMP_ERR_GENERROR; |
||
545 | } |
||
546 | } |
||
547 | |||
548 | return ERR_OK; |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * Service an internal or external event for SNMP GETBULKT. |
||
553 | * |
||
554 | * @param request points to the associated message process state |
||
555 | */ |
||
556 | static err_t |
||
557 | snmp_process_getbulk_request(struct snmp_request *request) |
||
558 | { |
||
559 | snmp_vb_enumerator_err_t err; |
||
560 | s32_t non_repeaters = request->non_repeaters; |
||
561 | s32_t repetitions; |
||
562 | u16_t repetition_offset = 0; |
||
563 | struct snmp_varbind_enumerator repetition_varbind_enumerator; |
||
564 | struct snmp_varbind vb; |
||
565 | vb.value = request->value_buffer; |
||
566 | |||
567 | if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) { |
||
568 | repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS); |
||
569 | } else { |
||
570 | repetitions = request->max_repetitions; |
||
571 | } |
||
572 | |||
573 | LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n")); |
||
574 | |||
575 | /* process non repeaters and first repetition */ |
||
576 | while (request->error_status == SNMP_ERR_NOERROR) { |
||
577 | if (non_repeaters == 0) { |
||
578 | repetition_offset = request->outbound_pbuf_stream.offset; |
||
579 | |||
580 | if (repetitions == 0) { |
||
581 | /* do not resolve repeaters when repetitions is set to 0 */ |
||
582 | break; |
||
583 | } |
||
584 | repetitions--; |
||
585 | } |
||
586 | |||
587 | err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); |
||
588 | if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { |
||
589 | /* no more varbinds in request */ |
||
590 | break; |
||
591 | } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { |
||
592 | /* malformed ASN.1, don't answer */ |
||
593 | return ERR_ARG; |
||
594 | } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) { |
||
595 | request->error_status = SNMP_ERR_GENERROR; |
||
596 | } else { |
||
597 | snmp_process_varbind(request, &vb, 1); |
||
598 | non_repeaters--; |
||
599 | } |
||
600 | } |
||
601 | |||
602 | /* process repetitions > 1 */ |
||
603 | while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) { |
||
604 | |||
605 | u8_t all_endofmibview = 1; |
||
606 | |||
607 | snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset); |
||
608 | repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */ |
||
609 | |||
610 | while (request->error_status == SNMP_ERR_NOERROR) { |
||
611 | vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */ |
||
612 | err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb); |
||
613 | if (err == SNMP_VB_ENUMERATOR_ERR_OK) { |
||
614 | vb.value = request->value_buffer; |
||
615 | snmp_process_varbind(request, &vb, 1); |
||
616 | |||
617 | if (request->error_status != SNMP_ERR_NOERROR) { |
||
618 | /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */ |
||
619 | request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; |
||
620 | } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) { |
||
621 | all_endofmibview = 0; |
||
622 | } |
||
623 | } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { |
||
624 | /* no more varbinds in request */ |
||
625 | break; |
||
626 | } else { |
||
627 | LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!")); |
||
628 | request->error_status = SNMP_ERR_GENERROR; |
||
629 | request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; |
||
630 | } |
||
631 | } |
||
632 | |||
633 | if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) { |
||
634 | /* stop when all varbinds in a loop return EndOfMibView */ |
||
635 | break; |
||
636 | } |
||
637 | |||
638 | repetitions--; |
||
639 | } |
||
640 | |||
641 | if (request->error_status == SNMP_ERR_TOOBIG) { |
||
642 | /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */ |
||
643 | request->error_status = SNMP_ERR_NOERROR; |
||
644 | } |
||
645 | |||
646 | return ERR_OK; |
||
647 | } |
||
648 | |||
649 | /** |
||
650 | * Service an internal or external event for SNMP SET. |
||
651 | * |
||
652 | * @param request points to the associated message process state |
||
653 | */ |
||
654 | static err_t |
||
655 | snmp_process_set_request(struct snmp_request *request) |
||
656 | { |
||
657 | snmp_vb_enumerator_err_t err; |
||
658 | struct snmp_varbind vb; |
||
659 | vb.value = request->value_buffer; |
||
660 | |||
661 | LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n")); |
||
662 | |||
663 | /* perform set test on all objects */ |
||
664 | while (request->error_status == SNMP_ERR_NOERROR) { |
||
665 | err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); |
||
666 | if (err == SNMP_VB_ENUMERATOR_ERR_OK) { |
||
667 | struct snmp_node_instance node_instance; |
||
668 | memset(&node_instance, 0, sizeof(node_instance)); |
||
669 | |||
670 | request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); |
||
671 | if (request->error_status == SNMP_ERR_NOERROR) { |
||
672 | if (node_instance.asn1_type != vb.type) { |
||
673 | request->error_status = SNMP_ERR_WRONGTYPE; |
||
674 | } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) { |
||
675 | request->error_status = SNMP_ERR_NOTWRITABLE; |
||
676 | } else { |
||
677 | if (node_instance.set_test != NULL) { |
||
678 | request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value); |
||
679 | } |
||
680 | } |
||
681 | |||
682 | if (node_instance.release_instance != NULL) { |
||
683 | node_instance.release_instance(&node_instance); |
||
684 | } |
||
685 | } |
||
686 | } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { |
||
687 | /* no more varbinds in request */ |
||
688 | break; |
||
689 | } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) { |
||
690 | request->error_status = SNMP_ERR_WRONGLENGTH; |
||
691 | } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { |
||
692 | /* malformed ASN.1, don't answer */ |
||
693 | return ERR_ARG; |
||
694 | } else { |
||
695 | request->error_status = SNMP_ERR_GENERROR; |
||
696 | } |
||
697 | } |
||
698 | |||
699 | /* perform real set operation on all objects */ |
||
700 | if (request->error_status == SNMP_ERR_NOERROR) { |
||
701 | snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); |
||
702 | while (request->error_status == SNMP_ERR_NOERROR) { |
||
703 | err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); |
||
704 | if (err == SNMP_VB_ENUMERATOR_ERR_OK) { |
||
705 | struct snmp_node_instance node_instance; |
||
706 | memset(&node_instance, 0, sizeof(node_instance)); |
||
707 | request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); |
||
708 | if (request->error_status == SNMP_ERR_NOERROR) { |
||
709 | if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) { |
||
710 | if (request->inbound_varbind_enumerator.varbind_count == 1) { |
||
711 | request->error_status = SNMP_ERR_COMMITFAILED; |
||
712 | } else { |
||
713 | /* we cannot undo the set operations done so far */ |
||
714 | request->error_status = SNMP_ERR_UNDOFAILED; |
||
715 | } |
||
716 | } |
||
717 | |||
718 | if (node_instance.release_instance != NULL) { |
||
719 | node_instance.release_instance(&node_instance); |
||
720 | } |
||
721 | } |
||
722 | } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { |
||
723 | /* no more varbinds in request */ |
||
724 | break; |
||
725 | } else { |
||
726 | /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */ |
||
727 | request->error_status = SNMP_ERR_GENERROR; |
||
728 | } |
||
729 | } |
||
730 | } |
||
731 | |||
732 | return ERR_OK; |
||
733 | } |
||
734 | |||
735 | #define PARSE_EXEC(code, retValue) \ |
||
736 | if ((code) != ERR_OK) { \ |
||
737 | LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \ |
||
738 | snmp_stats.inasnparseerrs++; \ |
||
739 | return retValue; \ |
||
740 | } |
||
741 | |||
742 | #define PARSE_ASSERT(cond, retValue) \ |
||
743 | if (!(cond)) { \ |
||
744 | LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \ |
||
745 | snmp_stats.inasnparseerrs++; \ |
||
746 | return retValue; \ |
||
747 | } |
||
748 | |||
749 | #define BUILD_EXEC(code, retValue) \ |
||
750 | if ((code) != ERR_OK) { \ |
||
751 | LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \ |
||
752 | return retValue; \ |
||
753 | } |
||
754 | |||
755 | #define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG) |
||
756 | #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG) |
||
757 | |||
758 | /** |
||
759 | * Checks and decodes incoming SNMP message header, logs header errors. |
||
760 | * |
||
761 | * @param request points to the current message request state return |
||
762 | * @return |
||
763 | * - ERR_OK SNMP header is sane and accepted |
||
764 | * - ERR_VAL SNMP header is either malformed or rejected |
||
765 | */ |
||
766 | static err_t |
||
767 | snmp_parse_inbound_frame(struct snmp_request *request) |
||
768 | { |
||
769 | struct snmp_pbuf_stream pbuf_stream; |
||
770 | struct snmp_asn1_tlv tlv; |
||
771 | s32_t parent_tlv_value_len; |
||
772 | s32_t s32_value; |
||
773 | err_t err; |
||
774 | #if LWIP_SNMP_V3 |
||
775 | snmpv3_auth_algo_t auth; |
||
776 | snmpv3_priv_algo_t priv; |
||
777 | #endif |
||
778 | |||
779 | IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); |
||
780 | |||
781 | /* decode main container consisting of version, community and PDU */ |
||
782 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
783 | IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length)); |
||
784 | parent_tlv_value_len = tlv.value_len; |
||
785 | |||
786 | /* decode version */ |
||
787 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
788 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
789 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
790 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
791 | |||
792 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); |
||
793 | |||
794 | if (((s32_value != SNMP_VERSION_1) && |
||
795 | (s32_value != SNMP_VERSION_2c) |
||
796 | #if LWIP_SNMP_V3 |
||
797 | && (s32_value != SNMP_VERSION_3) |
||
798 | #endif |
||
799 | ) |
||
800 | #if LWIP_SNMP_CONFIGURE_VERSIONS |
||
801 | || (!snmp_version_enabled(s32_value)) |
||
802 | #endif |
||
803 | ) { |
||
804 | /* unsupported SNMP version */ |
||
805 | snmp_stats.inbadversions++; |
||
806 | return ERR_ARG; |
||
807 | } |
||
808 | request->version = (u8_t)s32_value; |
||
809 | |||
810 | #if LWIP_SNMP_V3 |
||
811 | if (request->version == SNMP_VERSION_3) { |
||
812 | u16_t u16_value; |
||
813 | u16_t inbound_msgAuthenticationParameters_offset; |
||
814 | |||
815 | /* SNMPv3 doesn't use communities */ |
||
816 | /* @todo: Differentiate read/write access */ |
||
817 | strncpy((char *)request->community, snmp_community, SNMP_MAX_COMMUNITY_STR_LEN); |
||
818 | request->community[SNMP_MAX_COMMUNITY_STR_LEN] = 0; /* ensure NULL termination (strncpy does NOT guarantee it!) */ |
||
819 | request->community_strlen = (u16_t)strnlen((char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN); |
||
820 | |||
821 | /* RFC3414 globalData */ |
||
822 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
823 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); |
||
824 | parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); |
||
825 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
826 | |||
827 | /* decode msgID */ |
||
828 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
829 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
830 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
831 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
832 | |||
833 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); |
||
834 | request->msg_id = s32_value; |
||
835 | |||
836 | /* decode msgMaxSize */ |
||
837 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
838 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
839 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
840 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
841 | |||
842 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); |
||
843 | request->msg_max_size = s32_value; |
||
844 | |||
845 | /* decode msgFlags */ |
||
846 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
847 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
848 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
849 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
850 | |||
851 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); |
||
852 | request->msg_flags = (u8_t)s32_value; |
||
853 | |||
854 | /* decode msgSecurityModel */ |
||
855 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
856 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
857 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
858 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
859 | |||
860 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); |
||
861 | request->msg_security_model = s32_value; |
||
862 | |||
863 | /* RFC3414 msgSecurityParameters |
||
864 | * The User-based Security Model defines the contents of the OCTET |
||
865 | * STRING as a SEQUENCE. |
||
866 | * |
||
867 | * We skip the protective dummy OCTET STRING header |
||
868 | * to access the SEQUENCE header. |
||
869 | */ |
||
870 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
871 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
872 | parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); |
||
873 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
874 | |||
875 | /* msgSecurityParameters SEQUENCE header */ |
||
876 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
877 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); |
||
878 | parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); |
||
879 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
880 | |||
881 | /* decode msgAuthoritativeEngineID */ |
||
882 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
883 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
884 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
885 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
886 | |||
887 | IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id, |
||
888 | &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); |
||
889 | request->msg_authoritative_engine_id_len = (u8_t)u16_value; |
||
890 | |||
891 | /* msgAuthoritativeEngineBoots */ |
||
892 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
893 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
894 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
895 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
896 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots)); |
||
897 | |||
898 | /* msgAuthoritativeEngineTime */ |
||
899 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
900 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
901 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
902 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
903 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time)); |
||
904 | |||
905 | /* msgUserName */ |
||
906 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
907 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
908 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
909 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
910 | |||
911 | IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name, |
||
912 | &u16_value, SNMP_V3_MAX_USER_LENGTH)); |
||
913 | request->msg_user_name_len = (u8_t)u16_value; |
||
914 | |||
915 | /* msgAuthenticationParameters */ |
||
916 | memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); |
||
917 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
918 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
919 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
920 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
921 | /* Remember position */ |
||
922 | inbound_msgAuthenticationParameters_offset = pbuf_stream.offset; |
||
923 | LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset); |
||
924 | /* Read auth parameters */ |
||
925 | /* IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); */ |
||
926 | IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters, |
||
927 | &u16_value, tlv.value_len)); |
||
928 | request->msg_authentication_parameters_len = (u8_t)u16_value; |
||
929 | |||
930 | /* msgPrivacyParameters */ |
||
931 | memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); |
||
932 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
933 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
934 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
935 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
936 | |||
937 | IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters, |
||
938 | &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); |
||
939 | request->msg_privacy_parameters_len = (u8_t)u16_value; |
||
940 | |||
941 | /* validate securityParameters here (do this after decoding because we don't want to increase other counters for wrong frames) |
||
942 | * 1) securityParameters was correctly serialized if we reach here. |
||
943 | * 2) securityParameters are already cached. |
||
944 | * 3) if msgAuthoritativeEngineID is unknown, zero-length or too long: |
||
945 | b) https://tools.ietf.org/html/rfc3414#section-7 |
||
946 | */ |
||
947 | { |
||
948 | const char *eid; |
||
949 | u8_t eid_len; |
||
950 | |||
951 | snmpv3_get_engine_id(&eid, &eid_len); |
||
952 | |||
953 | if ((request->msg_authoritative_engine_id_len == 0) || |
||
954 | (request->msg_authoritative_engine_id_len != eid_len) || |
||
955 | (memcmp(eid, request->msg_authoritative_engine_id, eid_len) != 0)) { |
||
956 | snmp_stats.unknownengineids++; |
||
957 | request->msg_flags = 0; /* noauthnopriv */ |
||
958 | request->error_status = SNMP_ERR_UNKNOWN_ENGINEID; |
||
959 | return ERR_OK; |
||
960 | } |
||
961 | } |
||
962 | |||
963 | /* 4) verify username */ |
||
964 | if (snmpv3_get_user((char *)request->msg_user_name, &auth, NULL, &priv, NULL)) { |
||
965 | snmp_stats.unknownusernames++; |
||
966 | request->msg_flags = 0; /* noauthnopriv */ |
||
967 | request->error_status = SNMP_ERR_UNKNOWN_SECURITYNAME; |
||
968 | return ERR_OK; |
||
969 | } |
||
970 | |||
971 | /* 5) verify security level */ |
||
972 | switch (request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)) { |
||
973 | case SNMP_V3_NOAUTHNOPRIV: |
||
974 | if ((auth != SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) { |
||
975 | /* Invalid security level for user */ |
||
976 | snmp_stats.unsupportedseclevels++; |
||
977 | request->msg_flags = SNMP_V3_NOAUTHNOPRIV; |
||
978 | request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL; |
||
979 | return ERR_OK; |
||
980 | } |
||
981 | break; |
||
982 | #if LWIP_SNMP_V3_CRYPTO |
||
983 | case SNMP_V3_AUTHNOPRIV: |
||
984 | if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) { |
||
985 | /* Invalid security level for user */ |
||
986 | snmp_stats.unsupportedseclevels++; |
||
987 | request->msg_flags = SNMP_V3_NOAUTHNOPRIV; |
||
988 | request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL; |
||
989 | return ERR_OK; |
||
990 | } |
||
991 | break; |
||
992 | case SNMP_V3_AUTHPRIV: |
||
993 | if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv == SNMP_V3_PRIV_ALGO_INVAL)) { |
||
994 | /* Invalid security level for user */ |
||
995 | snmp_stats.unsupportedseclevels++; |
||
996 | request->msg_flags = SNMP_V3_NOAUTHNOPRIV; |
||
997 | request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL; |
||
998 | return ERR_OK; |
||
999 | } |
||
1000 | break; |
||
1001 | #endif |
||
1002 | default: |
||
1003 | snmp_stats.unsupportedseclevels++; |
||
1004 | request->msg_flags = SNMP_V3_NOAUTHNOPRIV; |
||
1005 | request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL; |
||
1006 | return ERR_OK; |
||
1007 | } |
||
1008 | |||
1009 | /* 6) if securitylevel specifies authentication, authenticate message. */ |
||
1010 | #if LWIP_SNMP_V3_CRYPTO |
||
1011 | if (request->msg_flags & SNMP_V3_AUTH_FLAG) { |
||
1012 | const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 }; |
||
1013 | u8_t key[20]; |
||
1014 | u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)]; |
||
1015 | struct snmp_pbuf_stream auth_stream; |
||
1016 | |||
1017 | if (request->msg_authentication_parameters_len > SNMP_V3_MAX_AUTH_PARAM_LENGTH) { |
||
1018 | snmp_stats.wrongdigests++; |
||
1019 | request->msg_flags = SNMP_V3_NOAUTHNOPRIV; |
||
1020 | request->error_status = SNMP_ERR_AUTHORIZATIONERROR; |
||
1021 | return ERR_OK; |
||
1022 | } |
||
1023 | |||
1024 | /* Rewind stream */ |
||
1025 | IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); |
||
1026 | IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&auth_stream, inbound_msgAuthenticationParameters_offset)); |
||
1027 | /* Set auth parameters to zero for verification */ |
||
1028 | IF_PARSE_EXEC(snmp_asn1_enc_raw(&auth_stream, zero_arr, request->msg_authentication_parameters_len)); |
||
1029 | |||
1030 | /* Verify authentication */ |
||
1031 | IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); |
||
1032 | |||
1033 | IF_PARSE_EXEC(snmpv3_get_user((char *)request->msg_user_name, &auth, key, NULL, NULL)); |
||
1034 | IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, auth, hmac)); |
||
1035 | |||
1036 | if (memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)) { |
||
1037 | snmp_stats.wrongdigests++; |
||
1038 | request->msg_flags = SNMP_V3_NOAUTHNOPRIV; |
||
1039 | request->error_status = SNMP_ERR_AUTHORIZATIONERROR; |
||
1040 | return ERR_OK; |
||
1041 | } |
||
1042 | |||
1043 | /* 7) if securitylevel specifies authentication, verify engineboots, enginetime and lastenginetime */ |
||
1044 | { |
||
1045 | s32_t boots = snmpv3_get_engine_boots_internal(); |
||
1046 | if ((request->msg_authoritative_engine_boots != boots) || (boots == 2147483647UL)) { |
||
1047 | snmp_stats.notintimewindows++; |
||
1048 | request->msg_flags = SNMP_V3_AUTHNOPRIV; |
||
1049 | request->error_status = SNMP_ERR_NOTINTIMEWINDOW; |
||
1050 | return ERR_OK; |
||
1051 | } |
||
1052 | } |
||
1053 | { |
||
1054 | s32_t time = snmpv3_get_engine_time_internal(); |
||
1055 | if (request->msg_authoritative_engine_time > time) { |
||
1056 | snmp_stats.notintimewindows++; |
||
1057 | request->msg_flags = SNMP_V3_AUTHNOPRIV; |
||
1058 | request->error_status = SNMP_ERR_NOTINTIMEWINDOW; |
||
1059 | return ERR_OK; |
||
1060 | } else if (time > 150) { |
||
1061 | if (request->msg_authoritative_engine_time < time - 150) { |
||
1062 | snmp_stats.notintimewindows++; |
||
1063 | request->msg_flags = SNMP_V3_AUTHNOPRIV; |
||
1064 | request->error_status = SNMP_ERR_NOTINTIMEWINDOW; |
||
1065 | return ERR_OK; |
||
1066 | } |
||
1067 | } |
||
1068 | } |
||
1069 | } |
||
1070 | #endif |
||
1071 | |||
1072 | /* 8) if securitylevel specifies privacy, decrypt message. */ |
||
1073 | #if LWIP_SNMP_V3_CRYPTO |
||
1074 | if (request->msg_flags & SNMP_V3_PRIV_FLAG) { |
||
1075 | /* Decrypt message */ |
||
1076 | |||
1077 | u8_t key[20]; |
||
1078 | |||
1079 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1080 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
1081 | parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); |
||
1082 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1083 | |||
1084 | IF_PARSE_EXEC(snmpv3_get_user((char *)request->msg_user_name, NULL, NULL, &priv, key)); |
||
1085 | if (snmpv3_crypt(&pbuf_stream, tlv.value_len, key, |
||
1086 | request->msg_privacy_parameters, request->msg_authoritative_engine_boots, |
||
1087 | request->msg_authoritative_engine_time, priv, SNMP_V3_PRIV_MODE_DECRYPT) != ERR_OK) { |
||
1088 | snmp_stats.decryptionerrors++; |
||
1089 | request->msg_flags = SNMP_V3_AUTHNOPRIV; |
||
1090 | request->error_status = SNMP_ERR_DECRYIPTION_ERROR; |
||
1091 | return ERR_OK; |
||
1092 | } |
||
1093 | } |
||
1094 | #endif |
||
1095 | /* 9) calculate max size of scoped pdu? |
||
1096 | * 10) securityname for user is retrieved from usertable? |
||
1097 | * 11) security data is cached? |
||
1098 | * 12) |
||
1099 | */ |
||
1100 | |||
1101 | /* Scoped PDU |
||
1102 | * Encryption context |
||
1103 | */ |
||
1104 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1105 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); |
||
1106 | parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); |
||
1107 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1108 | |||
1109 | /* contextEngineID */ |
||
1110 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1111 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
1112 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1113 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1114 | |||
1115 | IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id, |
||
1116 | &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); |
||
1117 | request->context_engine_id_len = (u8_t)u16_value; |
||
1118 | /* TODO: do we need to verify this contextengineid too? */ |
||
1119 | |||
1120 | /* contextName */ |
||
1121 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1122 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
1123 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1124 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1125 | |||
1126 | IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name, |
||
1127 | &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); |
||
1128 | request->context_name_len = (u8_t)u16_value; |
||
1129 | /* TODO: do we need to verify this contextname too? */ |
||
1130 | } else |
||
1131 | #endif |
||
1132 | { |
||
1133 | /* decode community */ |
||
1134 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1135 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); |
||
1136 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1137 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1138 | |||
1139 | err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN); |
||
1140 | if (err == ERR_MEM) { |
||
1141 | /* community string does not fit in our buffer -> its too long -> its invalid */ |
||
1142 | request->community_strlen = 0; |
||
1143 | snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len); |
||
1144 | } else { |
||
1145 | IF_PARSE_ASSERT(err == ERR_OK); |
||
1146 | } |
||
1147 | /* add zero terminator */ |
||
1148 | request->community[request->community_strlen] = 0; |
||
1149 | } |
||
1150 | |||
1151 | /* decode PDU type (next container level) */ |
||
1152 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1153 | IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length); |
||
1154 | request->inbound_padding_len = pbuf_stream.length - tlv.value_len; |
||
1155 | parent_tlv_value_len = tlv.value_len; |
||
1156 | |||
1157 | /* validate PDU type */ |
||
1158 | switch (tlv.type) { |
||
1159 | case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ): |
||
1160 | /* GetRequest PDU */ |
||
1161 | snmp_stats.ingetrequests++; |
||
1162 | break; |
||
1163 | case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ): |
||
1164 | /* GetNextRequest PDU */ |
||
1165 | snmp_stats.ingetnexts++; |
||
1166 | break; |
||
1167 | case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ): |
||
1168 | /* GetBulkRequest PDU */ |
||
1169 | if (request->version < SNMP_VERSION_2c) { |
||
1170 | /* RFC2089: invalid, drop packet */ |
||
1171 | return ERR_ARG; |
||
1172 | } |
||
1173 | break; |
||
1174 | case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ): |
||
1175 | /* SetRequest PDU */ |
||
1176 | snmp_stats.insetrequests++; |
||
1177 | break; |
||
1178 | default: |
||
1179 | /* unsupported input PDU for this agent (no parse error) */ |
||
1180 | LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \ |
||
1181 | return ERR_ARG; |
||
1182 | } |
||
1183 | request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK; |
||
1184 | request->request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP); |
||
1185 | |||
1186 | /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */ |
||
1187 | if (request->community_strlen == 0) { |
||
1188 | /* community string was too long or really empty*/ |
||
1189 | snmp_stats.inbadcommunitynames++; |
||
1190 | snmp_authfail_trap(); |
||
1191 | return ERR_ARG; |
||
1192 | } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { |
||
1193 | if (snmp_community_write[0] == 0) { |
||
1194 | /* our write community is empty, that means all our objects are readonly */ |
||
1195 | request->error_status = SNMP_ERR_NOTWRITABLE; |
||
1196 | request->error_index = 1; |
||
1197 | } else if (strncmp(snmp_community_write, (const char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { |
||
1198 | /* community name does not match */ |
||
1199 | snmp_stats.inbadcommunitynames++; |
||
1200 | snmp_authfail_trap(); |
||
1201 | return ERR_ARG; |
||
1202 | } |
||
1203 | } else { |
||
1204 | if (strncmp(snmp_community, (const char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { |
||
1205 | /* community name does not match */ |
||
1206 | snmp_stats.inbadcommunitynames++; |
||
1207 | snmp_authfail_trap(); |
||
1208 | return ERR_ARG; |
||
1209 | } |
||
1210 | } |
||
1211 | |||
1212 | /* decode request ID */ |
||
1213 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1214 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
1215 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1216 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1217 | |||
1218 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id)); |
||
1219 | |||
1220 | /* decode error status / non-repeaters */ |
||
1221 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1222 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
1223 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1224 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1225 | |||
1226 | if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { |
||
1227 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters)); |
||
1228 | if (request->non_repeaters < 0) { |
||
1229 | /* RFC 1905, 4.2.3 */ |
||
1230 | request->non_repeaters = 0; |
||
1231 | } |
||
1232 | } else { |
||
1233 | /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */ |
||
1234 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); |
||
1235 | IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR); |
||
1236 | } |
||
1237 | |||
1238 | /* decode error index / max-repetitions */ |
||
1239 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1240 | IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); |
||
1241 | parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1242 | IF_PARSE_ASSERT(parent_tlv_value_len > 0); |
||
1243 | |||
1244 | if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { |
||
1245 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions)); |
||
1246 | if (request->max_repetitions < 0) { |
||
1247 | /* RFC 1905, 4.2.3 */ |
||
1248 | request->max_repetitions = 0; |
||
1249 | } |
||
1250 | } else { |
||
1251 | IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index)); |
||
1252 | IF_PARSE_ASSERT(s32_value == 0); |
||
1253 | } |
||
1254 | |||
1255 | /* decode varbind-list type (next container level) */ |
||
1256 | IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); |
||
1257 | IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length)); |
||
1258 | |||
1259 | request->inbound_varbind_offset = pbuf_stream.offset; |
||
1260 | request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len; |
||
1261 | snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); |
||
1262 | |||
1263 | return ERR_OK; |
||
1264 | } |
||
1265 | |||
1266 | #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) |
||
1267 | |||
1268 | static err_t |
||
1269 | snmp_prepare_outbound_frame(struct snmp_request *request) |
||
1270 | { |
||
1271 | struct snmp_asn1_tlv tlv; |
||
1272 | struct snmp_pbuf_stream *pbuf_stream = &(request->outbound_pbuf_stream); |
||
1273 | |||
1274 | /* try allocating pbuf(s) for maximum response size */ |
||
1275 | request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM); |
||
1276 | if (request->outbound_pbuf == NULL) { |
||
1277 | return ERR_MEM; |
||
1278 | } |
||
1279 | |||
1280 | snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len); |
||
1281 | |||
1282 | /* 'Message' sequence */ |
||
1283 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); |
||
1284 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1285 | |||
1286 | /* version */ |
||
1287 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); |
||
1288 | snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len); |
||
1289 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1290 | OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) ); |
||
1291 | |||
1292 | #if LWIP_SNMP_V3 |
||
1293 | if (request->version < SNMP_VERSION_3) { |
||
1294 | #endif |
||
1295 | /* community */ |
||
1296 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen); |
||
1297 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1298 | OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); |
||
1299 | #if LWIP_SNMP_V3 |
||
1300 | } else { |
||
1301 | const char *id; |
||
1302 | |||
1303 | /* globalData */ |
||
1304 | request->outbound_msg_global_data_offset = pbuf_stream->offset; |
||
1305 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); |
||
1306 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1307 | |||
1308 | /* msgID */ |
||
1309 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); |
||
1310 | snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len); |
||
1311 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1312 | OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id)); |
||
1313 | |||
1314 | /* msgMaxSize */ |
||
1315 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); |
||
1316 | snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len); |
||
1317 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1318 | OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size)); |
||
1319 | |||
1320 | /* msgFlags */ |
||
1321 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1); |
||
1322 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1323 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1)); |
||
1324 | |||
1325 | /* msgSecurityModel */ |
||
1326 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); |
||
1327 | snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len); |
||
1328 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1329 | OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model)); |
||
1330 | |||
1331 | /* end of msgGlobalData */ |
||
1332 | request->outbound_msg_global_data_end = pbuf_stream->offset; |
||
1333 | |||
1334 | /* msgSecurityParameters */ |
||
1335 | request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset; |
||
1336 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0); |
||
1337 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1338 | |||
1339 | request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset; |
||
1340 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); |
||
1341 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1342 | |||
1343 | /* msgAuthoritativeEngineID */ |
||
1344 | snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len); |
||
1345 | MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len); |
||
1346 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len); |
||
1347 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1348 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len)); |
||
1349 | |||
1350 | request->msg_authoritative_engine_time = snmpv3_get_engine_time(); |
||
1351 | request->msg_authoritative_engine_boots = snmpv3_get_engine_boots(); |
||
1352 | |||
1353 | /* msgAuthoritativeEngineBoots */ |
||
1354 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); |
||
1355 | snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len); |
||
1356 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1357 | OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots)); |
||
1358 | |||
1359 | /* msgAuthoritativeEngineTime */ |
||
1360 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); |
||
1361 | snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len); |
||
1362 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1363 | OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time)); |
||
1364 | |||
1365 | /* msgUserName */ |
||
1366 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len); |
||
1367 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1368 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len)); |
||
1369 | |||
1370 | #if LWIP_SNMP_V3_CRYPTO |
||
1371 | /* msgAuthenticationParameters */ |
||
1372 | if (request->msg_flags & SNMP_V3_AUTH_FLAG) { |
||
1373 | memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); |
||
1374 | request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset; |
||
1375 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); |
||
1376 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1377 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); |
||
1378 | } else |
||
1379 | #endif |
||
1380 | { |
||
1381 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); |
||
1382 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1383 | } |
||
1384 | |||
1385 | #if LWIP_SNMP_V3_CRYPTO |
||
1386 | /* msgPrivacyParameters */ |
||
1387 | if (request->msg_flags & SNMP_V3_PRIV_FLAG) { |
||
1388 | snmpv3_build_priv_param(request->msg_privacy_parameters); |
||
1389 | |||
1390 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); |
||
1391 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1392 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); |
||
1393 | } else |
||
1394 | #endif |
||
1395 | { |
||
1396 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); |
||
1397 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1398 | } |
||
1399 | |||
1400 | /* End of msgSecurityParameters, so we can calculate the length of this sequence later */ |
||
1401 | request->outbound_msg_security_parameters_end = pbuf_stream->offset; |
||
1402 | |||
1403 | #if LWIP_SNMP_V3_CRYPTO |
||
1404 | /* For encryption we have to encapsulate the payload in an octet string */ |
||
1405 | if (request->msg_flags & SNMP_V3_PRIV_FLAG) { |
||
1406 | request->outbound_scoped_pdu_string_offset = pbuf_stream->offset; |
||
1407 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0); |
||
1408 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1409 | } |
||
1410 | #endif |
||
1411 | /* Scoped PDU |
||
1412 | * Encryption context |
||
1413 | */ |
||
1414 | request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset; |
||
1415 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); |
||
1416 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1417 | |||
1418 | /* contextEngineID */ |
||
1419 | snmpv3_get_engine_id(&id, &request->context_engine_id_len); |
||
1420 | MEMCPY(request->context_engine_id, id, request->context_engine_id_len); |
||
1421 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len); |
||
1422 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1423 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len)); |
||
1424 | |||
1425 | /* contextName */ |
||
1426 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len); |
||
1427 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1428 | OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len)); |
||
1429 | } |
||
1430 | #endif |
||
1431 | |||
1432 | /* 'PDU' sequence */ |
||
1433 | request->outbound_pdu_offset = pbuf_stream->offset; |
||
1434 | SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3, 0); |
||
1435 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1436 | |||
1437 | /* request ID */ |
||
1438 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); |
||
1439 | snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len); |
||
1440 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1441 | OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) ); |
||
1442 | |||
1443 | /* error status */ |
||
1444 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); |
||
1445 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1446 | request->outbound_error_status_offset = pbuf_stream->offset; |
||
1447 | OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); |
||
1448 | |||
1449 | /* error index */ |
||
1450 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); |
||
1451 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1452 | request->outbound_error_index_offset = pbuf_stream->offset; |
||
1453 | OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); |
||
1454 | |||
1455 | /* 'VarBindList' sequence */ |
||
1456 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); |
||
1457 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); |
||
1458 | |||
1459 | request->outbound_varbind_offset = pbuf_stream->offset; |
||
1460 | |||
1461 | return ERR_OK; |
||
1462 | } |
||
1463 | |||
1464 | /** Calculate the length of a varbind list */ |
||
1465 | err_t |
||
1466 | snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len) |
||
1467 | { |
||
1468 | /* calculate required lengths */ |
||
1469 | snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len); |
||
1470 | snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len); |
||
1471 | |||
1472 | if (varbind->value_len == 0) { |
||
1473 | len->value_value_len = 0; |
||
1474 | } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { |
||
1475 | len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA); |
||
1476 | } else { |
||
1477 | switch (varbind->type) { |
||
1478 | case SNMP_ASN1_TYPE_INTEGER: |
||
1479 | if (varbind->value_len != sizeof (s32_t)) { |
||
1480 | return ERR_VAL; |
||
1481 | } |
||
1482 | snmp_asn1_enc_s32t_cnt(*((s32_t *) varbind->value), &len->value_value_len); |
||
1483 | break; |
||
1484 | case SNMP_ASN1_TYPE_COUNTER: |
||
1485 | case SNMP_ASN1_TYPE_GAUGE: |
||
1486 | case SNMP_ASN1_TYPE_TIMETICKS: |
||
1487 | if (varbind->value_len != sizeof (u32_t)) { |
||
1488 | return ERR_VAL; |
||
1489 | } |
||
1490 | snmp_asn1_enc_u32t_cnt(*((u32_t *) varbind->value), &len->value_value_len); |
||
1491 | break; |
||
1492 | case SNMP_ASN1_TYPE_OCTET_STRING: |
||
1493 | case SNMP_ASN1_TYPE_IPADDR: |
||
1494 | case SNMP_ASN1_TYPE_OPAQUE: |
||
1495 | len->value_value_len = varbind->value_len; |
||
1496 | break; |
||
1497 | case SNMP_ASN1_TYPE_NULL: |
||
1498 | if (varbind->value_len != 0) { |
||
1499 | return ERR_VAL; |
||
1500 | } |
||
1501 | len->value_value_len = 0; |
||
1502 | break; |
||
1503 | case SNMP_ASN1_TYPE_OBJECT_ID: |
||
1504 | if ((varbind->value_len & 0x03) != 0) { |
||
1505 | return ERR_VAL; |
||
1506 | } |
||
1507 | snmp_asn1_enc_oid_cnt((u32_t *) varbind->value, varbind->value_len >> 2, &len->value_value_len); |
||
1508 | break; |
||
1509 | #if LWIP_HAVE_INT64 |
||
1510 | case SNMP_ASN1_TYPE_COUNTER64: |
||
1511 | if (varbind->value_len != sizeof(u64_t)) { |
||
1512 | return ERR_VAL; |
||
1513 | } |
||
1514 | snmp_asn1_enc_u64t_cnt(*(u64_t *)varbind->value, &len->value_value_len); |
||
1515 | break; |
||
1516 | #endif |
||
1517 | default: |
||
1518 | /* unsupported type */ |
||
1519 | return ERR_VAL; |
||
1520 | } |
||
1521 | } |
||
1522 | snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len); |
||
1523 | |||
1524 | len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len; |
||
1525 | snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len); |
||
1526 | |||
1527 | return ERR_OK; |
||
1528 | } |
||
1529 | |||
1530 | #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) |
||
1531 | |||
1532 | err_t |
||
1533 | snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbind) |
||
1534 | { |
||
1535 | struct snmp_asn1_tlv tlv; |
||
1536 | struct snmp_varbind_len len; |
||
1537 | err_t err; |
||
1538 | |||
1539 | err = snmp_varbind_length(varbind, &len); |
||
1540 | |||
1541 | if (err != ERR_OK) { |
||
1542 | return err; |
||
1543 | } |
||
1544 | |||
1545 | /* check length already before adding first data because in case of GetBulk, |
||
1546 | * data added so far is returned and therefore no partial data shall be added |
||
1547 | */ |
||
1548 | if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) { |
||
1549 | return ERR_BUF; |
||
1550 | } |
||
1551 | |||
1552 | /* 'VarBind' sequence */ |
||
1553 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len); |
||
1554 | OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1555 | |||
1556 | /* VarBind OID */ |
||
1557 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len); |
||
1558 | OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1559 | OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len)); |
||
1560 | |||
1561 | /* VarBind value */ |
||
1562 | SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len); |
||
1563 | OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); |
||
1564 | |||
1565 | if (len.value_value_len > 0) { |
||
1566 | if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { |
||
1567 | OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t *) varbind->value, len.value_value_len)); |
||
1568 | } else { |
||
1569 | switch (varbind->type) { |
||
1570 | case SNMP_ASN1_TYPE_INTEGER: |
||
1571 | OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t *) varbind->value))); |
||
1572 | break; |
||
1573 | case SNMP_ASN1_TYPE_COUNTER: |
||
1574 | case SNMP_ASN1_TYPE_GAUGE: |
||
1575 | case SNMP_ASN1_TYPE_TIMETICKS: |
||
1576 | OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t *) varbind->value))); |
||
1577 | break; |
||
1578 | case SNMP_ASN1_TYPE_OCTET_STRING: |
||
1579 | case SNMP_ASN1_TYPE_IPADDR: |
||
1580 | case SNMP_ASN1_TYPE_OPAQUE: |
||
1581 | OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t *) varbind->value, len.value_value_len)); |
||
1582 | len.value_value_len = varbind->value_len; |
||
1583 | break; |
||
1584 | case SNMP_ASN1_TYPE_OBJECT_ID: |
||
1585 | OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t *) varbind->value, varbind->value_len / sizeof (u32_t))); |
||
1586 | break; |
||
1587 | #if LWIP_HAVE_INT64 |
||
1588 | case SNMP_ASN1_TYPE_COUNTER64: |
||
1589 | OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, *(u64_t *) varbind->value)); |
||
1590 | break; |
||
1591 | #endif |
||
1592 | default: |
||
1593 | LWIP_ASSERT("Unknown variable type", 0); |
||
1594 | break; |
||
1595 | } |
||
1596 | } |
||
1597 | } |
||
1598 | |||
1599 | return ERR_OK; |
||
1600 | } |
||
1601 | |||
1602 | static err_t |
||
1603 | snmp_complete_outbound_frame(struct snmp_request *request) |
||
1604 | { |
||
1605 | struct snmp_asn1_tlv tlv; |
||
1606 | u16_t frame_size; |
||
1607 | u8_t outbound_padding = 0; |
||
1608 | |||
1609 | if (request->version == SNMP_VERSION_1) { |
||
1610 | if (request->error_status != SNMP_ERR_NOERROR) { |
||
1611 | /* map v2c error codes to v1 compliant error code (according to RFC 2089) */ |
||
1612 | switch (request->error_status) { |
||
1613 | /* mapping of implementation specific "virtual" error codes |
||
1614 | * (during processing of frame we already stored them in error_status field, |
||
1615 | * so no need to check all varbinds here for those exceptions as suggested by RFC) */ |
||
1616 | case SNMP_ERR_NOSUCHINSTANCE: |
||
1617 | case SNMP_ERR_NOSUCHOBJECT: |
||
1618 | case SNMP_ERR_ENDOFMIBVIEW: |
||
1619 | request->error_status = SNMP_ERR_NOSUCHNAME; |
||
1620 | break; |
||
1621 | /* mapping according to RFC */ |
||
1622 | case SNMP_ERR_WRONGVALUE: |
||
1623 | case SNMP_ERR_WRONGENCODING: |
||
1624 | case SNMP_ERR_WRONGTYPE: |
||
1625 | case SNMP_ERR_WRONGLENGTH: |
||
1626 | case SNMP_ERR_INCONSISTENTVALUE: |
||
1627 | request->error_status = SNMP_ERR_BADVALUE; |
||
1628 | break; |
||
1629 | case SNMP_ERR_NOACCESS: |
||
1630 | case SNMP_ERR_NOTWRITABLE: |
||
1631 | case SNMP_ERR_NOCREATION: |
||
1632 | case SNMP_ERR_INCONSISTENTNAME: |
||
1633 | case SNMP_ERR_AUTHORIZATIONERROR: |
||
1634 | request->error_status = SNMP_ERR_NOSUCHNAME; |
||
1635 | break; |
||
1636 | case SNMP_ERR_RESOURCEUNAVAILABLE: |
||
1637 | case SNMP_ERR_COMMITFAILED: |
||
1638 | case SNMP_ERR_UNDOFAILED: |
||
1639 | default: |
||
1640 | request->error_status = SNMP_ERR_GENERROR; |
||
1641 | break; |
||
1642 | } |
||
1643 | } |
||
1644 | } else { |
||
1645 | if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { |
||
1646 | /* map error codes to according to RFC 1905 (4.2.5. The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */ |
||
1647 | switch (request->error_status) { |
||
1648 | case SNMP_ERR_NOSUCHINSTANCE: |
||
1649 | case SNMP_ERR_NOSUCHOBJECT: |
||
1650 | case SNMP_ERR_ENDOFMIBVIEW: |
||
1651 | request->error_status = SNMP_ERR_NOTWRITABLE; |
||
1652 | break; |
||
1653 | default: |
||
1654 | break; |
||
1655 | } |
||
1656 | } |
||
1657 | |||
1658 | if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { |
||
1659 | /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */ |
||
1660 | LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n")); |
||
1661 | return ERR_ARG; |
||
1662 | } |
||
1663 | } |
||
1664 | |||
1665 | if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) { |
||
1666 | /* all inbound vars are returned in response without any modification for error responses and successful set requests*/ |
||
1667 | struct snmp_pbuf_stream inbound_stream; |
||
1668 | OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) ); |
||
1669 | OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) ); |
||
1670 | OF_BUILD_EXEC( snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0) ); |
||
1671 | } |
||
1672 | |||
1673 | frame_size = request->outbound_pbuf_stream.offset; |
||
1674 | |||
1675 | #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO |
||
1676 | /* Calculate padding for encryption */ |
||
1677 | if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { |
||
1678 | u8_t i; |
||
1679 | outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07; |
||
1680 | for (i = 0; i < outbound_padding; i++) { |
||
1681 | OF_BUILD_EXEC( snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0) ); |
||
1682 | } |
||
1683 | } |
||
1684 | #endif |
||
1685 | |||
1686 | /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */ |
||
1687 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size + outbound_padding - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ |
||
1688 | OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) ); |
||
1689 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); |
||
1690 | |||
1691 | #if LWIP_SNMP_V3 |
||
1692 | if (request->version == SNMP_VERSION_3) { |
||
1693 | /* complete missing length in 'globalData' sequence */ |
||
1694 | /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ |
||
1695 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end |
||
1696 | - request->outbound_msg_global_data_offset - 1 - 1); |
||
1697 | OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset)); |
||
1698 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); |
||
1699 | |||
1700 | /* complete missing length in 'msgSecurityParameters' sequence */ |
||
1701 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end |
||
1702 | - request->outbound_msg_security_parameters_str_offset - 1 - 1); |
||
1703 | OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset)); |
||
1704 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); |
||
1705 | |||
1706 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end |
||
1707 | - request->outbound_msg_security_parameters_seq_offset - 1 - 1); |
||
1708 | OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset)); |
||
1709 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); |
||
1710 | |||
1711 | /* complete missing length in scoped PDU sequence */ |
||
1712 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3); |
||
1713 | OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset)); |
||
1714 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); |
||
1715 | } |
||
1716 | #endif |
||
1717 | |||
1718 | /* complete missing length in 'PDU' sequence */ |
||
1719 | SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3, |
||
1720 | frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ |
||
1721 | OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) ); |
||
1722 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); |
||
1723 | |||
1724 | /* process and encode final error status */ |
||
1725 | if (request->error_status != 0) { |
||
1726 | u16_t len; |
||
1727 | snmp_asn1_enc_s32t_cnt(request->error_status, &len); |
||
1728 | if (len != 1) { |
||
1729 | /* error, we only reserved one byte for it */ |
||
1730 | return ERR_ARG; |
||
1731 | } |
||
1732 | OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) ); |
||
1733 | OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) ); |
||
1734 | |||
1735 | /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */ |
||
1736 | switch (request->error_status) { |
||
1737 | case SNMP_ERR_TOOBIG: |
||
1738 | snmp_stats.outtoobigs++; |
||
1739 | break; |
||
1740 | case SNMP_ERR_NOSUCHNAME: |
||
1741 | snmp_stats.outnosuchnames++; |
||
1742 | break; |
||
1743 | case SNMP_ERR_BADVALUE: |
||
1744 | snmp_stats.outbadvalues++; |
||
1745 | break; |
||
1746 | case SNMP_ERR_GENERROR: |
||
1747 | default: |
||
1748 | snmp_stats.outgenerrs++; |
||
1749 | break; |
||
1750 | } |
||
1751 | |||
1752 | if (request->error_status == SNMP_ERR_TOOBIG) { |
||
1753 | request->error_index = 0; /* defined by RFC 1157 */ |
||
1754 | } else if (request->error_index == 0) { |
||
1755 | /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ |
||
1756 | request->error_index = request->inbound_varbind_enumerator.varbind_count; |
||
1757 | } |
||
1758 | } else { |
||
1759 | if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { |
||
1760 | snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count; |
||
1761 | } else { |
||
1762 | snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count; |
||
1763 | } |
||
1764 | } |
||
1765 | |||
1766 | /* encode final error index*/ |
||
1767 | if (request->error_index != 0) { |
||
1768 | u16_t len; |
||
1769 | snmp_asn1_enc_s32t_cnt(request->error_index, &len); |
||
1770 | if (len != 1) { |
||
1771 | /* error, we only reserved one byte for it */ |
||
1772 | return ERR_VAL; |
||
1773 | } |
||
1774 | OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) ); |
||
1775 | OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) ); |
||
1776 | } |
||
1777 | |||
1778 | /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */ |
||
1779 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset); |
||
1780 | OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ |
||
1781 | OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); |
||
1782 | |||
1783 | /* Authenticate response */ |
||
1784 | #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO |
||
1785 | /* Encrypt response */ |
||
1786 | if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { |
||
1787 | u8_t key[20]; |
||
1788 | snmpv3_priv_algo_t algo; |
||
1789 | |||
1790 | /* complete missing length in PDU sequence */ |
||
1791 | OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); |
||
1792 | OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset)); |
||
1793 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding |
||
1794 | - request->outbound_scoped_pdu_string_offset - 1 - 3); |
||
1795 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); |
||
1796 | |||
1797 | OF_BUILD_EXEC(snmpv3_get_user((char *)request->msg_user_name, NULL, NULL, &algo, key)); |
||
1798 | |||
1799 | OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key, |
||
1800 | request->msg_privacy_parameters, request->msg_authoritative_engine_boots, |
||
1801 | request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT)); |
||
1802 | } |
||
1803 | |||
1804 | if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) { |
||
1805 | u8_t key[20]; |
||
1806 | snmpv3_auth_algo_t algo; |
||
1807 | u8_t hmac[20]; |
||
1808 | |||
1809 | OF_BUILD_EXEC(snmpv3_get_user((char *)request->msg_user_name, &algo, key, NULL, NULL)); |
||
1810 | OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), |
||
1811 | request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); |
||
1812 | OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac)); |
||
1813 | |||
1814 | MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH); |
||
1815 | OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, |
||
1816 | request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); |
||
1817 | OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream, |
||
1818 | request->outbound_msg_authentication_parameters_offset)); |
||
1819 | |||
1820 | SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); |
||
1821 | OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv)); |
||
1822 | OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream, |
||
1823 | request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); |
||
1824 | } |
||
1825 | #endif |
||
1826 | |||
1827 | pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding); |
||
1828 | |||
1829 | snmp_stats.outgetresponses++; |
||
1830 | snmp_stats.outpkts++; |
||
1831 | |||
1832 | return ERR_OK; |
||
1833 | } |
||
1834 | |||
1835 | static void |
||
1836 | snmp_execute_write_callbacks(struct snmp_request *request) |
||
1837 | { |
||
1838 | struct snmp_varbind_enumerator inbound_varbind_enumerator; |
||
1839 | struct snmp_varbind vb; |
||
1840 | |||
1841 | snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); |
||
1842 | vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */ |
||
1843 | |||
1844 | while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) { |
||
1845 | snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg); |
||
1846 | } |
||
1847 | } |
||
1848 | |||
1849 | |||
1850 | /* ----------------------------------------------------------------------- */ |
||
1851 | /* VarBind enumerator methods */ |
||
1852 | /* ----------------------------------------------------------------------- */ |
||
1853 | |||
1854 | void |
||
1855 | snmp_vb_enumerator_init(struct snmp_varbind_enumerator *enumerator, struct pbuf *p, u16_t offset, u16_t length) |
||
1856 | { |
||
1857 | snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length); |
||
1858 | enumerator->varbind_count = 0; |
||
1859 | } |
||
1860 | |||
1861 | #define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) |
||
1862 | #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) |
||
1863 | |||
1864 | snmp_vb_enumerator_err_t |
||
1865 | snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator *enumerator, struct snmp_varbind *varbind) |
||
1866 | { |
||
1867 | struct snmp_asn1_tlv tlv; |
||
1868 | u16_t varbind_len; |
||
1869 | err_t err; |
||
1870 | |||
1871 | if (enumerator->pbuf_stream.length == 0) { |
||
1872 | return SNMP_VB_ENUMERATOR_ERR_EOVB; |
||
1873 | } |
||
1874 | enumerator->varbind_count++; |
||
1875 | |||
1876 | /* decode varbind itself (parent container of a varbind) */ |
||
1877 | VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); |
||
1878 | VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length)); |
||
1879 | varbind_len = tlv.value_len; |
||
1880 | |||
1881 | /* decode varbind name (object id) */ |
||
1882 | VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); |
||
1883 | VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length)); |
||
1884 | |||
1885 | VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN)); |
||
1886 | varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv); |
||
1887 | |||
1888 | /* decode varbind value (object id) */ |
||
1889 | VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); |
||
1890 | VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length)); |
||
1891 | varbind->type = tlv.type; |
||
1892 | |||
1893 | /* shall the value be decoded ? */ |
||
1894 | if (varbind->value != NULL) { |
||
1895 | switch (varbind->type) { |
||
1896 | case SNMP_ASN1_TYPE_INTEGER: |
||
1897 | VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t *)varbind->value)); |
||
1898 | varbind->value_len = sizeof(s32_t); |
||
1899 | break; |
||
1900 | case SNMP_ASN1_TYPE_COUNTER: |
||
1901 | case SNMP_ASN1_TYPE_GAUGE: |
||
1902 | case SNMP_ASN1_TYPE_TIMETICKS: |
||
1903 | VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t *)varbind->value)); |
||
1904 | varbind->value_len = sizeof(u32_t); |
||
1905 | break; |
||
1906 | case SNMP_ASN1_TYPE_OCTET_STRING: |
||
1907 | case SNMP_ASN1_TYPE_OPAQUE: |
||
1908 | err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t *)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE); |
||
1909 | if (err == ERR_MEM) { |
||
1910 | return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; |
||
1911 | } |
||
1912 | VB_PARSE_ASSERT(err == ERR_OK); |
||
1913 | break; |
||
1914 | case SNMP_ASN1_TYPE_NULL: |
||
1915 | varbind->value_len = 0; |
||
1916 | break; |
||
1917 | case SNMP_ASN1_TYPE_OBJECT_ID: |
||
1918 | /* misuse tlv.length_len as OID_length transporter */ |
||
1919 | err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t *)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN); |
||
1920 | if (err == ERR_MEM) { |
||
1921 | return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; |
||
1922 | } |
||
1923 | VB_PARSE_ASSERT(err == ERR_OK); |
||
1924 | varbind->value_len = tlv.length_len * sizeof(u32_t); |
||
1925 | break; |
||
1926 | case SNMP_ASN1_TYPE_IPADDR: |
||
1927 | if (tlv.value_len == 4) { |
||
1928 | /* must be exactly 4 octets! */ |
||
1929 | VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t *)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE)); |
||
1930 | } else { |
||
1931 | VB_PARSE_ASSERT(0); |
||
1932 | } |
||
1933 | break; |
||
1934 | #if LWIP_HAVE_INT64 |
||
1935 | case SNMP_ASN1_TYPE_COUNTER64: |
||
1936 | VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u64_t *)varbind->value)); |
||
1937 | varbind->value_len = sizeof(u64_t); |
||
1938 | break; |
||
1939 | #endif |
||
1940 | default: |
||
1941 | VB_PARSE_ASSERT(0); |
||
1942 | break; |
||
1943 | } |
||
1944 | } else { |
||
1945 | snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len); |
||
1946 | varbind->value_len = tlv.value_len; |
||
1947 | } |
||
1948 | |||
1949 | return SNMP_VB_ENUMERATOR_ERR_OK; |
||
1950 | } |
||
1951 | |||
1952 | #endif /* LWIP_SNMP */ |