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