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