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