Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_snmp_msg.c Source File

lwip_snmp_msg.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * SNMP message processing (RFC1157).
00004  */
00005 
00006 /*
00007  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
00008  * Copyright (c) 2016 Elias Oenal.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * Author: Christiaan Simons <christiaan.simons@axon.tv>
00034  *         Martin Hentschel <info@cl-soft.de>
00035  *         Elias Oenal <lwip@eliasoenal.com>
00036  */
00037 
00038 #include "lwip/apps/snmp_opts.h"
00039 
00040 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
00041 
00042 #include "snmp_msg.h"
00043 #include "snmp_asn1.h"
00044 #include "snmp_core_priv.h"
00045 #include "lwip/ip_addr.h"
00046 #include "lwip/stats.h"
00047 
00048 #if LWIP_SNMP_V3
00049 #include "lwip/apps/snmpv3.h"
00050 #include "snmpv3_priv.h"
00051 #ifdef LWIP_HOOK_FILENAME
00052 #include LWIP_HOOK_FILENAME
00053 #endif
00054 #endif
00055 
00056 #include <string.h>
00057 
00058 #define SNMP_V3_AUTH_FLAG      0x01
00059 #define SNMP_V3_PRIV_FLAG      0x02
00060 
00061 /* Security levels */
00062 #define SNMP_V3_NOAUTHNOPRIV   0x00
00063 #define SNMP_V3_AUTHNOPRIV     SNMP_V3_AUTH_FLAG
00064 #define SNMP_V3_AUTHPRIV       (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)
00065 
00066 /* public (non-static) constants */
00067 /** SNMP community string */
00068 const char *snmp_community = SNMP_COMMUNITY;
00069 /** SNMP community string for write access */
00070 const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
00071 /** SNMP community string for sending traps */
00072 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
00073 
00074 snmp_write_callback_fct snmp_write_callback     = NULL;
00075 void                   *snmp_write_callback_arg = NULL;
00076 
00077 #if LWIP_SNMP_CONFIGURE_VERSIONS
00078 
00079 static u8_t v1_enabled = 1;
00080 static u8_t v2c_enabled = 1;
00081 static u8_t v3_enabled = 1;
00082 
00083 static u8_t
00084 snmp_version_enabled(u8_t version)
00085 {
00086   if (version == SNMP_VERSION_1) {
00087     return v1_enabled;
00088   } else if (version == SNMP_VERSION_2c) {
00089     return v2c_enabled;
00090   }
00091 #if LWIP_SNMP_V3
00092   else if (version == SNMP_VERSION_3) {
00093     return v3_enabled;
00094   }
00095 #endif
00096   else {
00097     LWIP_ASSERT("Invalid SNMP version", 0);
00098     return 0;
00099   }
00100 }
00101 
00102 u8_t
00103 snmp_v1_enabled(void)
00104 {
00105   return snmp_version_enabled(SNMP_VERSION_1);
00106 }
00107 
00108 u8_t
00109 snmp_v2c_enabled(void)
00110 {
00111   return snmp_version_enabled(SNMP_VERSION_2c);
00112 }
00113 
00114 u8_t
00115 snmp_v3_enabled(void)
00116 {
00117   return snmp_version_enabled(SNMP_VERSION_3);
00118 }
00119 
00120 static void
00121 snmp_version_enable(u8_t version, u8_t enable)
00122 {
00123   if (version == SNMP_VERSION_1) {
00124     v1_enabled = enable;
00125   } else if (version == SNMP_VERSION_2c) {
00126     v2c_enabled = enable;
00127   }
00128 #if LWIP_SNMP_V3
00129   else if (version == SNMP_VERSION_3) {
00130     v3_enabled = enable;
00131   }
00132 #endif
00133   else {
00134     LWIP_ASSERT("Invalid SNMP version", 0);
00135   }
00136 }
00137 
00138 void
00139 snmp_v1_enable(u8_t enable)
00140 {
00141   snmp_version_enable(SNMP_VERSION_1, enable);
00142 }
00143 
00144 void
00145 snmp_v2c_enable(u8_t enable)
00146 {
00147   snmp_version_enable(SNMP_VERSION_2c, enable);
00148 }
00149 
00150 void
00151 snmp_v3_enable(u8_t enable)
00152 {
00153   snmp_version_enable(SNMP_VERSION_3, enable);
00154 }
00155 
00156 #endif
00157 
00158 /**
00159  * @ingroup snmp_core
00160  * Returns current SNMP community string.
00161  * @return current SNMP community string
00162  */
00163 const char *
00164 snmp_get_community(void)
00165 {
00166   return snmp_community;
00167 }
00168 
00169 /**
00170  * @ingroup snmp_core
00171  * Sets SNMP community string.
00172  * The string itself (its storage) must be valid throughout the whole life of
00173  * program (or until it is changed to sth else).
00174  *
00175  * @param community is a pointer to new community string
00176  */
00177 void
00178 snmp_set_community(const char *const community)
00179 {
00180   LWIP_ASSERT_CORE_LOCKED();
00181   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
00182   snmp_community = community;
00183 }
00184 
00185 /**
00186  * @ingroup snmp_core
00187  * Returns current SNMP write-access community string.
00188  * @return current SNMP write-access community string
00189  */
00190 const char *
00191 snmp_get_community_write(void)
00192 {
00193   return snmp_community_write;
00194 }
00195 
00196 /**
00197  * @ingroup snmp_traps
00198  * Returns current SNMP community string used for sending traps.
00199  * @return current SNMP community string used for sending traps
00200  */
00201 const char *
00202 snmp_get_community_trap(void)
00203 {
00204   return snmp_community_trap;
00205 }
00206 
00207 /**
00208  * @ingroup snmp_core
00209  * Sets SNMP community string for write-access.
00210  * The string itself (its storage) must be valid throughout the whole life of
00211  * program (or until it is changed to sth else).
00212  *
00213  * @param community is a pointer to new write-access community string
00214  */
00215 void
00216 snmp_set_community_write(const char *const community)
00217 {
00218   LWIP_ASSERT_CORE_LOCKED();
00219   LWIP_ASSERT("community string must not be NULL", community != NULL);
00220   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
00221   snmp_community_write = community;
00222 }
00223 
00224 /**
00225  * @ingroup snmp_traps
00226  * Sets SNMP community string used for sending traps.
00227  * The string itself (its storage) must be valid throughout the whole life of
00228  * program (or until it is changed to sth else).
00229  *
00230  * @param community is a pointer to new trap community string
00231  */
00232 void
00233 snmp_set_community_trap(const char *const community)
00234 {
00235   LWIP_ASSERT_CORE_LOCKED();
00236   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
00237   snmp_community_trap = community;
00238 }
00239 
00240 /**
00241  * @ingroup snmp_core
00242  * Callback fired on every successful write access
00243  */
00244 void
00245 snmp_set_write_callback(snmp_write_callback_fct write_callback, void *callback_arg)
00246 {
00247   LWIP_ASSERT_CORE_LOCKED();
00248   snmp_write_callback     = write_callback;
00249   snmp_write_callback_arg = callback_arg;
00250 }
00251 
00252 /* ----------------------------------------------------------------------- */
00253 /* forward declarations */
00254 /* ----------------------------------------------------------------------- */
00255 
00256 static err_t snmp_process_get_request(struct snmp_request *request);
00257 static err_t snmp_process_getnext_request(struct snmp_request *request);
00258 static err_t snmp_process_getbulk_request(struct snmp_request *request);
00259 static err_t snmp_process_set_request(struct snmp_request *request);
00260 
00261 static err_t snmp_parse_inbound_frame(struct snmp_request *request);
00262 static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
00263 static err_t snmp_complete_outbound_frame(struct snmp_request *request);
00264 static void snmp_execute_write_callbacks(struct snmp_request *request);
00265 
00266 
00267 /* ----------------------------------------------------------------------- */
00268 /* implementation */
00269 /* ----------------------------------------------------------------------- */
00270 
00271 void
00272 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port)
00273 {
00274   err_t err;
00275   struct snmp_request request;
00276 
00277   memset(&request, 0, sizeof(request));
00278   request.handle       = handle;
00279   request.source_ip    = source_ip;
00280   request.source_port  = port;
00281   request.inbound_pbuf = p;
00282 
00283   snmp_stats.inpkts++;
00284 
00285   err = snmp_parse_inbound_frame(&request);
00286   if (err == ERR_OK) {
00287     err = snmp_prepare_outbound_frame(&request);
00288     if (err == ERR_OK) {
00289 
00290       if (request.error_status == SNMP_ERR_NOERROR) {
00291         /* only process frame if we do not already have an error to return (e.g. all readonly) */
00292         if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) {
00293           err = snmp_process_get_request(&request);
00294         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) {
00295           err = snmp_process_getnext_request(&request);
00296         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
00297           err = snmp_process_getbulk_request(&request);
00298         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
00299           err = snmp_process_set_request(&request);
00300         }
00301       }
00302 #if LWIP_SNMP_V3
00303       else {
00304         struct snmp_varbind vb;
00305 
00306         vb.next = NULL;
00307         vb.prev = NULL;
00308         vb.type = SNMP_ASN1_TYPE_COUNTER32;
00309         vb.value_len = sizeof(u32_t);
00310 
00311         switch (request.error_status) {
00312           case SNMP_ERR_AUTHORIZATIONERROR: {
00313             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
00314             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
00315             vb.value = &snmp_stats.wrongdigests;
00316           }
00317           break;
00318           case SNMP_ERR_UNKNOWN_ENGINEID: {
00319             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
00320             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
00321             vb.value = &snmp_stats.unknownengineids;
00322           }
00323           break;
00324           case SNMP_ERR_UNKNOWN_SECURITYNAME: {
00325             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
00326             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
00327             vb.value = &snmp_stats.unknownusernames;
00328           }
00329           break;
00330           case SNMP_ERR_UNSUPPORTED_SECLEVEL: {
00331             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
00332             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
00333             vb.value = &snmp_stats.unsupportedseclevels;
00334           }
00335           break;
00336           case SNMP_ERR_NOTINTIMEWINDOW: {
00337             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
00338             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
00339             vb.value = &snmp_stats.notintimewindows;
00340           }
00341           break;
00342           case SNMP_ERR_DECRYIPTION_ERROR: {
00343             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
00344             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
00345             vb.value = &snmp_stats.decryptionerrors;
00346           }
00347           break;
00348           default:
00349             /* Unknown or unhandled error_status */
00350             err = ERR_ARG;
00351         }
00352 
00353         if (err == ERR_OK) {
00354           snmp_append_outbound_varbind(&(request.outbound_pbuf_stream), &vb);
00355           request.error_status = SNMP_ERR_NOERROR;
00356         }
00357 
00358         request.request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_REPORT);
00359         request.request_id = request.msg_id;
00360       }
00361 #endif
00362 
00363       if (err == ERR_OK) {
00364         err = snmp_complete_outbound_frame(&request);
00365 
00366         if (err == ERR_OK) {
00367           err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port);
00368 
00369           if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)
00370               && (request.error_status == SNMP_ERR_NOERROR)
00371               && (snmp_write_callback != NULL)) {
00372             /* raise write notification for all written objects */
00373             snmp_execute_write_callbacks(&request);
00374           }
00375         }
00376       }
00377     }
00378 
00379     if (request.outbound_pbuf != NULL) {
00380       pbuf_free(request.outbound_pbuf);
00381     }
00382   }
00383 }
00384 
00385 static u8_t
00386 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance *node_instance, void *validate_arg)
00387 {
00388   if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) {
00389     return SNMP_ERR_NOSUCHINSTANCE;
00390   }
00391 
00392 #if LWIP_HAVE_INT64
00393   if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request *)validate_arg)->version == SNMP_VERSION_1)) {
00394     /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */
00395     return SNMP_ERR_NOSUCHINSTANCE;
00396   }
00397 #endif
00398 
00399   return SNMP_ERR_NOERROR;
00400 }
00401 
00402 static void
00403 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
00404 {
00405   err_t err;
00406   struct snmp_node_instance node_instance;
00407   memset(&node_instance, 0, sizeof(node_instance));
00408 
00409   if (get_next) {
00410     struct snmp_obj_id result_oid;
00411     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);
00412 
00413     if (request->error_status == SNMP_ERR_NOERROR) {
00414       snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
00415     }
00416   } else {
00417     request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);
00418 
00419     if (request->error_status == SNMP_ERR_NOERROR) {
00420       /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
00421       request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);
00422 
00423       if (request->error_status != SNMP_ERR_NOERROR) {
00424         if (node_instance.release_instance != NULL) {
00425           node_instance.release_instance(&node_instance);
00426         }
00427       }
00428     }
00429   }
00430 
00431   if (request->error_status != SNMP_ERR_NOERROR)  {
00432     if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
00433       if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) {
00434         /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
00435         vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
00436         vb->value_len = 0;
00437 
00438         err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb);
00439         if (err == ERR_OK) {
00440           /* we stored the exception in varbind -> go on */
00441           request->error_status = SNMP_ERR_NOERROR;
00442         } else if (err == ERR_BUF) {
00443           request->error_status = SNMP_ERR_TOOBIG;
00444         } else {
00445           request->error_status = SNMP_ERR_GENERROR;
00446         }
00447       }
00448     } else {
00449       /* according to RFC 1157/1905, all other errors only return genError */
00450       request->error_status = SNMP_ERR_GENERROR;
00451     }
00452   } else {
00453     s16_t len = node_instance.get_value(&node_instance, vb->value);
00454 
00455     if (len >= 0) {
00456       vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */
00457       vb->type = node_instance.asn1_type;
00458 
00459       LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);
00460       err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb);
00461 
00462       if (err == ERR_BUF) {
00463         request->error_status = SNMP_ERR_TOOBIG;
00464       } else if (err != ERR_OK) {
00465         request->error_status = SNMP_ERR_GENERROR;
00466       }
00467     } else {
00468       request->error_status = SNMP_ERR_GENERROR;
00469     }
00470 
00471     if (node_instance.release_instance != NULL) {
00472       node_instance.release_instance(&node_instance);
00473     }
00474   }
00475 }
00476 
00477 
00478 /**
00479  * Service an internal or external event for SNMP GET.
00480  *
00481  * @param request points to the associated message process state
00482  */
00483 static err_t
00484 snmp_process_get_request(struct snmp_request *request)
00485 {
00486   snmp_vb_enumerator_err_t err;
00487   struct snmp_varbind vb;
00488   vb.value = request->value_buffer;
00489 
00490   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n"));
00491 
00492   while (request->error_status == SNMP_ERR_NOERROR) {
00493     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00494     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00495       if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
00496         snmp_process_varbind(request, &vb, 0);
00497       } else {
00498         request->error_status = SNMP_ERR_GENERROR;
00499       }
00500     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00501       /* no more varbinds in request */
00502       break;
00503     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00504       /* malformed ASN.1, don't answer */
00505       return ERR_ARG;
00506     } else {
00507       request->error_status = SNMP_ERR_GENERROR;
00508     }
00509   }
00510 
00511   return ERR_OK;
00512 }
00513 
00514 /**
00515  * Service an internal or external event for SNMP GET.
00516  *
00517  * @param request points to the associated message process state
00518  */
00519 static err_t
00520 snmp_process_getnext_request(struct snmp_request *request)
00521 {
00522   snmp_vb_enumerator_err_t err;
00523   struct snmp_varbind vb;
00524   vb.value = request->value_buffer;
00525 
00526   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n"));
00527 
00528   while (request->error_status == SNMP_ERR_NOERROR) {
00529     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00530     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00531       if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
00532         snmp_process_varbind(request, &vb, 1);
00533       } else {
00534         request->error_status = SNMP_ERR_GENERROR;
00535       }
00536     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00537       /* no more varbinds in request */
00538       break;
00539     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00540       /* malformed ASN.1, don't answer */
00541       return ERR_ARG;
00542     } else {
00543       request->error_status = SNMP_ERR_GENERROR;
00544     }
00545   }
00546 
00547   return ERR_OK;
00548 }
00549 
00550 /**
00551  * Service an internal or external event for SNMP GETBULKT.
00552  *
00553  * @param request points to the associated message process state
00554  */
00555 static err_t
00556 snmp_process_getbulk_request(struct snmp_request *request)
00557 {
00558   snmp_vb_enumerator_err_t err;
00559   s32_t non_repeaters     = request->non_repeaters;
00560   s32_t repetitions;
00561   u16_t repetition_offset = 0;
00562   struct snmp_varbind_enumerator repetition_varbind_enumerator;
00563   struct snmp_varbind vb;
00564   vb.value = request->value_buffer;
00565 
00566   if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) {
00567     repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS);
00568   } else {
00569     repetitions = request->max_repetitions;
00570   }
00571 
00572   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n"));
00573 
00574   /* process non repeaters and first repetition */
00575   while (request->error_status == SNMP_ERR_NOERROR) {
00576     if (non_repeaters == 0) {
00577       repetition_offset = request->outbound_pbuf_stream.offset;
00578 
00579       if (repetitions == 0) {
00580         /* do not resolve repeaters when repetitions is set to 0 */
00581         break;
00582       }
00583       repetitions--;
00584     }
00585 
00586     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00587     if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00588       /* no more varbinds in request */
00589       break;
00590     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00591       /* malformed ASN.1, don't answer */
00592       return ERR_ARG;
00593     } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) {
00594       request->error_status = SNMP_ERR_GENERROR;
00595     } else {
00596       snmp_process_varbind(request, &vb, 1);
00597       non_repeaters--;
00598     }
00599   }
00600 
00601   /* process repetitions > 1 */
00602   while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) {
00603 
00604     u8_t all_endofmibview = 1;
00605 
00606     snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset);
00607     repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */
00608 
00609     while (request->error_status == SNMP_ERR_NOERROR) {
00610       vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */
00611       err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb);
00612       if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00613         vb.value = request->value_buffer;
00614         snmp_process_varbind(request, &vb, 1);
00615 
00616         if (request->error_status != SNMP_ERR_NOERROR) {
00617           /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */
00618           request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
00619         } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) {
00620           all_endofmibview = 0;
00621         }
00622       } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00623         /* no more varbinds in request */
00624         break;
00625       } else {
00626         LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!"));
00627         request->error_status = SNMP_ERR_GENERROR;
00628         request->error_index  = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
00629       }
00630     }
00631 
00632     if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) {
00633       /* stop when all varbinds in a loop return EndOfMibView */
00634       break;
00635     }
00636 
00637     repetitions--;
00638   }
00639 
00640   if (request->error_status == SNMP_ERR_TOOBIG) {
00641     /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */
00642     request->error_status = SNMP_ERR_NOERROR;
00643   }
00644 
00645   return ERR_OK;
00646 }
00647 
00648 /**
00649  * Service an internal or external event for SNMP SET.
00650  *
00651  * @param request points to the associated message process state
00652  */
00653 static err_t
00654 snmp_process_set_request(struct snmp_request *request)
00655 {
00656   snmp_vb_enumerator_err_t err;
00657   struct snmp_varbind vb;
00658   vb.value = request->value_buffer;
00659 
00660   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n"));
00661 
00662   /* perform set test on all objects */
00663   while (request->error_status == SNMP_ERR_NOERROR) {
00664     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00665     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00666       struct snmp_node_instance node_instance;
00667       memset(&node_instance, 0, sizeof(node_instance));
00668 
00669       request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
00670       if (request->error_status == SNMP_ERR_NOERROR) {
00671         if (node_instance.asn1_type != vb.type) {
00672           request->error_status = SNMP_ERR_WRONGTYPE;
00673         } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
00674           request->error_status = SNMP_ERR_NOTWRITABLE;
00675         } else {
00676           if (node_instance.set_test != NULL) {
00677             request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value);
00678           }
00679         }
00680 
00681         if (node_instance.release_instance != NULL) {
00682           node_instance.release_instance(&node_instance);
00683         }
00684       }
00685     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00686       /* no more varbinds in request */
00687       break;
00688     } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
00689       request->error_status = SNMP_ERR_WRONGLENGTH;
00690     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00691       /* malformed ASN.1, don't answer */
00692       return ERR_ARG;
00693     } else {
00694       request->error_status = SNMP_ERR_GENERROR;
00695     }
00696   }
00697 
00698   /* perform real set operation on all objects */
00699   if (request->error_status == SNMP_ERR_NOERROR) {
00700     snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
00701     while (request->error_status == SNMP_ERR_NOERROR) {
00702       err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00703       if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00704         struct snmp_node_instance node_instance;
00705         memset(&node_instance, 0, sizeof(node_instance));
00706         request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
00707         if (request->error_status == SNMP_ERR_NOERROR) {
00708           if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) {
00709             if (request->inbound_varbind_enumerator.varbind_count == 1) {
00710               request->error_status = SNMP_ERR_COMMITFAILED;
00711             } else {
00712               /* we cannot undo the set operations done so far */
00713               request->error_status = SNMP_ERR_UNDOFAILED;
00714             }
00715           }
00716 
00717           if (node_instance.release_instance != NULL) {
00718             node_instance.release_instance(&node_instance);
00719           }
00720         }
00721       } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00722         /* no more varbinds in request */
00723         break;
00724       } else {
00725         /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */
00726         request->error_status = SNMP_ERR_GENERROR;
00727       }
00728     }
00729   }
00730 
00731   return ERR_OK;
00732 }
00733 
00734 #define PARSE_EXEC(code, retValue) \
00735   if ((code) != ERR_OK) { \
00736     LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \
00737     snmp_stats.inasnparseerrs++; \
00738     return retValue; \
00739   }
00740 
00741 #define PARSE_ASSERT(cond, retValue) \
00742   if (!(cond)) { \
00743     LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \
00744     snmp_stats.inasnparseerrs++; \
00745     return retValue; \
00746   }
00747 
00748 #define BUILD_EXEC(code, retValue) \
00749   if ((code) != ERR_OK) { \
00750     LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \
00751     return retValue; \
00752   }
00753 
00754 #define IF_PARSE_EXEC(code)   PARSE_EXEC(code, ERR_ARG)
00755 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG)
00756 
00757 /**
00758  * Checks and decodes incoming SNMP message header, logs header errors.
00759  *
00760  * @param request points to the current message request state return
00761  * @return
00762  * - ERR_OK SNMP header is sane and accepted
00763  * - ERR_VAL SNMP header is either malformed or rejected
00764  */
00765 static err_t
00766 snmp_parse_inbound_frame(struct snmp_request *request)
00767 {
00768   struct snmp_pbuf_stream pbuf_stream;
00769   struct snmp_asn1_tlv tlv;
00770   s32_t parent_tlv_value_len;
00771   s32_t s32_value;
00772   err_t err;
00773 #if LWIP_SNMP_V3
00774   snmpv3_auth_algo_t auth;
00775   snmpv3_priv_algo_t priv;
00776 #endif
00777 
00778   IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
00779 
00780   /* decode main container consisting of version, community and PDU */
00781   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00782   IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
00783   parent_tlv_value_len = tlv.value_len;
00784 
00785   /* decode version */
00786   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00787   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00788   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00789   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00790 
00791   IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00792 
00793   if (((s32_value != SNMP_VERSION_1) &&
00794        (s32_value != SNMP_VERSION_2c)
00795 #if LWIP_SNMP_V3
00796        && (s32_value != SNMP_VERSION_3)
00797 #endif
00798       )
00799 #if LWIP_SNMP_CONFIGURE_VERSIONS
00800       || (!snmp_version_enabled(s32_value))
00801 #endif
00802      ) {
00803     /* unsupported SNMP version */
00804     snmp_stats.inbadversions++;
00805     return ERR_ARG;
00806   }
00807   request->version = (u8_t)s32_value;
00808 
00809 #if LWIP_SNMP_V3
00810   if (request->version == SNMP_VERSION_3) {
00811     u16_t u16_value;
00812     u16_t inbound_msgAuthenticationParameters_offset;
00813 
00814     /* SNMPv3 doesn't use communities */
00815     /* @todo: Differentiate read/write access */
00816     strncpy((char *)request->community, snmp_community, SNMP_MAX_COMMUNITY_STR_LEN);
00817     request->community[SNMP_MAX_COMMUNITY_STR_LEN] = 0; /* ensure NULL termination (strncpy does NOT guarantee it!) */
00818     request->community_strlen = (u16_t)strnlen((char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN);
00819 
00820     /* RFC3414 globalData */
00821     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00822     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
00823     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00824     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00825 
00826     /* decode msgID */
00827     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00828     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00829     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00830     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00831 
00832     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00833     request->msg_id = s32_value;
00834 
00835     /* decode msgMaxSize */
00836     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00837     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00838     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00839     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00840 
00841     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00842     request->msg_max_size = s32_value;
00843 
00844     /* decode msgFlags */
00845     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00846     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00847     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00848     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00849 
00850     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00851     request->msg_flags = (u8_t)s32_value;
00852 
00853     /* decode msgSecurityModel */
00854     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00855     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00856     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00857     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00858 
00859     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00860     request->msg_security_model = s32_value;
00861 
00862     /* RFC3414 msgSecurityParameters
00863      * The User-based Security Model defines the contents of the OCTET
00864      * STRING as a SEQUENCE.
00865      *
00866      * We skip the protective dummy OCTET STRING header
00867      * to access the SEQUENCE header.
00868      */
00869     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00870     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00871     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00872     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00873 
00874     /* msgSecurityParameters SEQUENCE header */
00875     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00876     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
00877     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00878     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00879 
00880     /* decode msgAuthoritativeEngineID */
00881     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00882     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00883     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00884     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00885 
00886     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id,
00887                                     &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
00888     request->msg_authoritative_engine_id_len = (u8_t)u16_value;
00889 
00890     /* msgAuthoritativeEngineBoots */
00891     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00892     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00893     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00894     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00895     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots));
00896 
00897     /* msgAuthoritativeEngineTime */
00898     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00899     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00900     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00901     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00902     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time));
00903 
00904     /* msgUserName */
00905     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00906     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00907     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00908     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00909 
00910     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name,
00911                                     &u16_value, SNMP_V3_MAX_USER_LENGTH));
00912     request->msg_user_name_len = (u8_t)u16_value;
00913 
00914     /* msgAuthenticationParameters */
00915     memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
00916     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00917     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00918     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00919     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00920     /* Remember position */
00921     inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
00922     LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset);
00923     /* Read auth parameters */
00924     /* IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); */
00925     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters,
00926                                     &u16_value, tlv.value_len));
00927     request->msg_authentication_parameters_len = (u8_t)u16_value;
00928 
00929     /* msgPrivacyParameters */
00930     memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
00931     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00932     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00933     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00934     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00935 
00936     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters,
00937                                     &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
00938     request->msg_privacy_parameters_len = (u8_t)u16_value;
00939 
00940     /* validate securityParameters here (do this after decoding because we don't want to increase other counters for wrong frames)
00941      * 1) securityParameters was correctly serialized if we reach here.
00942      * 2) securityParameters are already cached.
00943      * 3) if msgAuthoritativeEngineID is unknown, zero-length or too long:
00944          b) https://tools.ietf.org/html/rfc3414#section-7
00945      */
00946     {
00947       const char *eid;
00948       u8_t eid_len;
00949 
00950       snmpv3_get_engine_id(&eid, &eid_len);
00951 
00952       if ((request->msg_authoritative_engine_id_len == 0) ||
00953           (request->msg_authoritative_engine_id_len != eid_len) ||
00954           (memcmp(eid, request->msg_authoritative_engine_id, eid_len) != 0)) {
00955         snmp_stats.unknownengineids++;
00956         request->msg_flags = 0; /* noauthnopriv */
00957         request->error_status = SNMP_ERR_UNKNOWN_ENGINEID;
00958         return ERR_OK;
00959       }
00960     }
00961 
00962     /* 4) verify username */
00963     if (snmpv3_get_user((char *)request->msg_user_name, &auth, NULL, &priv, NULL)) {
00964       snmp_stats.unknownusernames++;
00965       request->msg_flags = 0; /* noauthnopriv */
00966       request->error_status = SNMP_ERR_UNKNOWN_SECURITYNAME;
00967       return ERR_OK;
00968     }
00969 
00970     /* 5) verify security level */
00971     switch (request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)) {
00972       case SNMP_V3_NOAUTHNOPRIV:
00973         if ((auth != SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) {
00974           /* Invalid security level for user */
00975           snmp_stats.unsupportedseclevels++;
00976           request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
00977           request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
00978           return ERR_OK;
00979         }
00980         break;
00981 #if LWIP_SNMP_V3_CRYPTO
00982       case SNMP_V3_AUTHNOPRIV:
00983         if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) {
00984           /* Invalid security level for user */
00985           snmp_stats.unsupportedseclevels++;
00986           request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
00987           request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
00988           return ERR_OK;
00989         }
00990         break;
00991       case SNMP_V3_AUTHPRIV:
00992         if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv == SNMP_V3_PRIV_ALGO_INVAL)) {
00993           /* Invalid security level for user */
00994           snmp_stats.unsupportedseclevels++;
00995           request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
00996           request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
00997           return ERR_OK;
00998         }
00999         break;
01000 #endif
01001       default:
01002         snmp_stats.unsupportedseclevels++;
01003         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
01004         request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
01005         return ERR_OK;
01006     }
01007 
01008     /* 6) if securitylevel specifies authentication, authenticate message. */
01009 #if LWIP_SNMP_V3_CRYPTO
01010     if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
01011       const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 };
01012       u8_t key[20];
01013       u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)];
01014       struct snmp_pbuf_stream auth_stream;
01015 
01016       if (request->msg_authentication_parameters_len > SNMP_V3_MAX_AUTH_PARAM_LENGTH) {
01017         snmp_stats.wrongdigests++;
01018         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
01019         request->error_status = SNMP_ERR_AUTHORIZATIONERROR;
01020         return ERR_OK;
01021       }
01022 
01023       /* Rewind stream */
01024       IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
01025       IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&auth_stream, inbound_msgAuthenticationParameters_offset));
01026       /* Set auth parameters to zero for verification */
01027       IF_PARSE_EXEC(snmp_asn1_enc_raw(&auth_stream, zero_arr, request->msg_authentication_parameters_len));
01028 
01029       /* Verify authentication */
01030       IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
01031 
01032       IF_PARSE_EXEC(snmpv3_get_user((char *)request->msg_user_name, &auth, key, NULL, NULL));
01033       IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, auth, hmac));
01034 
01035       if (memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)) {
01036         snmp_stats.wrongdigests++;
01037         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
01038         request->error_status = SNMP_ERR_AUTHORIZATIONERROR;
01039         return ERR_OK;
01040       }
01041 
01042       /* 7) if securitylevel specifies authentication, verify engineboots, enginetime and lastenginetime */
01043       {
01044         s32_t boots = snmpv3_get_engine_boots_internal();
01045         if ((request->msg_authoritative_engine_boots != boots) || (boots == 2147483647UL)) {
01046           snmp_stats.notintimewindows++;
01047           request->msg_flags = SNMP_V3_AUTHNOPRIV;
01048           request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
01049           return ERR_OK;
01050         }
01051       }
01052       {
01053         s32_t time = snmpv3_get_engine_time_internal();
01054         if (request->msg_authoritative_engine_time > (time + 150)) {
01055           snmp_stats.notintimewindows++;
01056           request->msg_flags = SNMP_V3_AUTHNOPRIV;
01057           request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
01058           return ERR_OK;
01059         } else if (time > 150) {
01060           if (request->msg_authoritative_engine_time < (time - 150)) {
01061             snmp_stats.notintimewindows++;
01062             request->msg_flags = SNMP_V3_AUTHNOPRIV;
01063             request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
01064             return ERR_OK;
01065           }
01066         }
01067       }
01068     }
01069 #endif
01070 
01071     /* 8) if securitylevel specifies privacy, decrypt message. */
01072 #if LWIP_SNMP_V3_CRYPTO
01073     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
01074       /* Decrypt message */
01075 
01076       u8_t key[20];
01077 
01078       IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01079       IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
01080       parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
01081       IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01082 
01083       IF_PARSE_EXEC(snmpv3_get_user((char *)request->msg_user_name, NULL, NULL, &priv, key));
01084       if (snmpv3_crypt(&pbuf_stream, tlv.value_len, key,
01085                        request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
01086                        request->msg_authoritative_engine_time, priv, SNMP_V3_PRIV_MODE_DECRYPT) != ERR_OK) {
01087         snmp_stats.decryptionerrors++;
01088         request->msg_flags = SNMP_V3_AUTHNOPRIV;
01089         request->error_status = SNMP_ERR_DECRYIPTION_ERROR;
01090         return ERR_OK;
01091       }
01092     }
01093 #endif
01094     /* 9) calculate max size of scoped pdu?
01095      * 10) securityname for user is retrieved from usertable?
01096      * 11) security data is cached?
01097      * 12)
01098      */
01099 
01100     /* Scoped PDU
01101      * Encryption context
01102      */
01103     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01104     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
01105     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
01106     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01107 
01108     /* contextEngineID */
01109     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01110     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
01111     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01112     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01113 
01114     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id,
01115                                     &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
01116     request->context_engine_id_len = (u8_t)u16_value;
01117     /* TODO: do we need to verify this contextengineid too? */
01118 
01119     /* contextName */
01120     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01121     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
01122     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01123     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01124 
01125     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name,
01126                                     &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
01127     request->context_name_len = (u8_t)u16_value;
01128     /* TODO: do we need to verify this contextname too? */
01129   } else
01130 #endif
01131   {
01132     /* decode community */
01133     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01134     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
01135     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01136     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01137 
01138     err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
01139     if (err == ERR_MEM) {
01140       /* community string does not fit in our buffer -> its too long -> its invalid */
01141       request->community_strlen = 0;
01142       snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
01143     } else {
01144       IF_PARSE_ASSERT(err == ERR_OK);
01145     }
01146     /* add zero terminator */
01147     request->community[request->community_strlen] = 0;
01148   }
01149 
01150   /* decode PDU type (next container level) */
01151   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01152   IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length);
01153   request->inbound_padding_len = pbuf_stream.length - tlv.value_len;
01154   parent_tlv_value_len = tlv.value_len;
01155 
01156   /* validate PDU type */
01157   switch (tlv.type) {
01158     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
01159       /* GetRequest PDU */
01160       snmp_stats.ingetrequests++;
01161       break;
01162     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
01163       /* GetNextRequest PDU */
01164       snmp_stats.ingetnexts++;
01165       break;
01166     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
01167       /* GetBulkRequest PDU */
01168       if (request->version < SNMP_VERSION_2c) {
01169         /* RFC2089: invalid, drop packet */
01170         return ERR_ARG;
01171       }
01172       break;
01173     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
01174       /* SetRequest PDU */
01175       snmp_stats.insetrequests++;
01176       break;
01177     default:
01178       /* unsupported input PDU for this agent (no parse error) */
01179       LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
01180       return ERR_ARG;
01181   }
01182   request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;
01183   request->request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP);
01184 
01185   /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
01186   if (request->community_strlen == 0) {
01187     /* community string was too long or really empty*/
01188     snmp_stats.inbadcommunitynames++;
01189     snmp_authfail_trap();
01190     return ERR_ARG;
01191   } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
01192     if (snmp_community_write[0] == 0) {
01193       /* our write community is empty, that means all our objects are readonly */
01194       request->error_status = SNMP_ERR_NOTWRITABLE;
01195       request->error_index  = 1;
01196     } else if (strncmp(snmp_community_write, (const char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
01197       /* community name does not match */
01198       snmp_stats.inbadcommunitynames++;
01199       snmp_authfail_trap();
01200       return ERR_ARG;
01201     }
01202   } else {
01203     if (strncmp(snmp_community, (const char *)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
01204       /* community name does not match */
01205       snmp_stats.inbadcommunitynames++;
01206       snmp_authfail_trap();
01207       return ERR_ARG;
01208     }
01209   }
01210 
01211   /* decode request ID */
01212   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01213   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
01214   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01215   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01216 
01217   IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));
01218 
01219   /* decode error status / non-repeaters */
01220   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01221   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
01222   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01223   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01224 
01225   if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
01226     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
01227     if (request->non_repeaters < 0) {
01228       /* RFC 1905, 4.2.3 */
01229       request->non_repeaters = 0;
01230     }
01231   } else {
01232     /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
01233     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
01234     IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
01235   }
01236 
01237   /* decode error index / max-repetitions */
01238   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01239   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
01240   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01241   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
01242 
01243   if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
01244     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
01245     if (request->max_repetitions < 0) {
01246       /* RFC 1905, 4.2.3 */
01247       request->max_repetitions = 0;
01248     }
01249   } else {
01250     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
01251     IF_PARSE_ASSERT(s32_value == 0);
01252   }
01253 
01254   /* decode varbind-list type (next container level) */
01255   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
01256   IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length));
01257 
01258   request->inbound_varbind_offset = pbuf_stream.offset;
01259   request->inbound_varbind_len    = pbuf_stream.length - request->inbound_padding_len;
01260   snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
01261 
01262   return ERR_OK;
01263 }
01264 
01265 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
01266 
01267 static err_t
01268 snmp_prepare_outbound_frame(struct snmp_request *request)
01269 {
01270   struct snmp_asn1_tlv tlv;
01271   struct snmp_pbuf_stream *pbuf_stream = &(request->outbound_pbuf_stream);
01272 
01273   /* try allocating pbuf(s) for maximum response size */
01274   request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM);
01275   if (request->outbound_pbuf == NULL) {
01276     return ERR_MEM;
01277   }
01278 
01279   snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len);
01280 
01281   /* 'Message' sequence */
01282   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
01283   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01284 
01285   /* version */
01286   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01287   snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len);
01288   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01289   OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) );
01290 
01291 #if LWIP_SNMP_V3
01292   if (request->version < SNMP_VERSION_3) {
01293 #endif
01294     /* community */
01295     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen);
01296     OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01297     OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
01298 #if LWIP_SNMP_V3
01299   } else {
01300     const char *id;
01301 
01302     /* globalData */
01303     request->outbound_msg_global_data_offset = pbuf_stream->offset;
01304     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
01305     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01306 
01307     /* msgID */
01308     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01309     snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len);
01310     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01311     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id));
01312 
01313     /* msgMaxSize */
01314     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01315     snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len);
01316     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01317     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size));
01318 
01319     /* msgFlags */
01320     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1);
01321     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01322     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1));
01323 
01324     /* msgSecurityModel */
01325     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01326     snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len);
01327     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01328     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model));
01329 
01330     /* end of msgGlobalData */
01331     request->outbound_msg_global_data_end = pbuf_stream->offset;
01332 
01333     /* msgSecurityParameters */
01334     request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset;
01335     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0);
01336     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01337 
01338     request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset;
01339     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
01340     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01341 
01342     /* msgAuthoritativeEngineID */
01343     snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
01344     MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
01345     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len);
01346     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01347     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len));
01348 
01349     request->msg_authoritative_engine_time = snmpv3_get_engine_time();
01350     request->msg_authoritative_engine_boots = snmpv3_get_engine_boots();
01351 
01352     /* msgAuthoritativeEngineBoots */
01353     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01354     snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len);
01355     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01356     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots));
01357 
01358     /* msgAuthoritativeEngineTime */
01359     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01360     snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len);
01361     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01362     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time));
01363 
01364     /* msgUserName */
01365     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len);
01366     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01367     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len));
01368 
01369 #if LWIP_SNMP_V3_CRYPTO
01370     /* msgAuthenticationParameters */
01371     if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
01372       memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01373       request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset;
01374       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01375       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01376       OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
01377     } else
01378 #endif
01379     {
01380       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
01381       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01382     }
01383 
01384 #if LWIP_SNMP_V3_CRYPTO
01385     /* msgPrivacyParameters */
01386     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
01387       snmpv3_build_priv_param(request->msg_privacy_parameters);
01388 
01389       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
01390       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01391       OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
01392     } else
01393 #endif
01394     {
01395       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
01396       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01397     }
01398 
01399     /* End of msgSecurityParameters, so we can calculate the length of this sequence later */
01400     request->outbound_msg_security_parameters_end = pbuf_stream->offset;
01401 
01402 #if LWIP_SNMP_V3_CRYPTO
01403     /* For encryption we have to encapsulate the payload in an octet string */
01404     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
01405       request->outbound_scoped_pdu_string_offset = pbuf_stream->offset;
01406       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0);
01407       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01408     }
01409 #endif
01410     /* Scoped PDU
01411      * Encryption context
01412      */
01413     request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset;
01414     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
01415     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01416 
01417     /* contextEngineID */
01418     snmpv3_get_engine_id(&id, &request->context_engine_id_len);
01419     MEMCPY(request->context_engine_id, id, request->context_engine_id_len);
01420     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len);
01421     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01422     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
01423 
01424     /* contextName */
01425     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len);
01426     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01427     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len));
01428   }
01429 #endif
01430 
01431   /* 'PDU' sequence */
01432   request->outbound_pdu_offset = pbuf_stream->offset;
01433   SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3, 0);
01434   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01435 
01436   /* request ID */
01437   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01438   snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len);
01439   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01440   OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) );
01441 
01442   /* error status */
01443   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01444   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01445   request->outbound_error_status_offset = pbuf_stream->offset;
01446   OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
01447 
01448   /* error index */
01449   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01450   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01451   request->outbound_error_index_offset = pbuf_stream->offset;
01452   OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
01453 
01454   /* 'VarBindList' sequence */
01455   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
01456   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01457 
01458   request->outbound_varbind_offset = pbuf_stream->offset;
01459 
01460   return ERR_OK;
01461 }
01462 
01463 /** Calculate the length of a varbind list */
01464 err_t
01465 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len)
01466 {
01467   /* calculate required lengths */
01468   snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len);
01469   snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len);
01470 
01471   if (varbind->value_len == 0) {
01472     len->value_value_len = 0;
01473   } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
01474     len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA);
01475   } else {
01476     switch (varbind->type) {
01477       case SNMP_ASN1_TYPE_INTEGER:
01478         if (varbind->value_len != sizeof (s32_t)) {
01479           return ERR_VAL;
01480         }
01481         snmp_asn1_enc_s32t_cnt(*((s32_t *) varbind->value), &len->value_value_len);
01482         break;
01483       case SNMP_ASN1_TYPE_COUNTER:
01484       case SNMP_ASN1_TYPE_GAUGE:
01485       case SNMP_ASN1_TYPE_TIMETICKS:
01486         if (varbind->value_len != sizeof (u32_t)) {
01487           return ERR_VAL;
01488         }
01489         snmp_asn1_enc_u32t_cnt(*((u32_t *) varbind->value), &len->value_value_len);
01490         break;
01491       case SNMP_ASN1_TYPE_OCTET_STRING:
01492       case SNMP_ASN1_TYPE_IPADDR:
01493       case SNMP_ASN1_TYPE_OPAQUE:
01494         len->value_value_len = varbind->value_len;
01495         break;
01496       case SNMP_ASN1_TYPE_NULL:
01497         if (varbind->value_len != 0) {
01498           return ERR_VAL;
01499         }
01500         len->value_value_len = 0;
01501         break;
01502       case SNMP_ASN1_TYPE_OBJECT_ID:
01503         if ((varbind->value_len & 0x03) != 0) {
01504           return ERR_VAL;
01505         }
01506         snmp_asn1_enc_oid_cnt((u32_t *) varbind->value, varbind->value_len >> 2, &len->value_value_len);
01507         break;
01508 #if LWIP_HAVE_INT64
01509       case SNMP_ASN1_TYPE_COUNTER64:
01510         if (varbind->value_len != sizeof(u64_t)) {
01511           return ERR_VAL;
01512         }
01513         snmp_asn1_enc_u64t_cnt(*(u64_t *)varbind->value, &len->value_value_len);
01514         break;
01515 #endif
01516       default:
01517         /* unsupported type */
01518         return ERR_VAL;
01519     }
01520   }
01521   snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len);
01522 
01523   len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len;
01524   snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len);
01525 
01526   return ERR_OK;
01527 }
01528 
01529 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
01530 
01531 err_t
01532 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbind)
01533 {
01534   struct snmp_asn1_tlv tlv;
01535   struct snmp_varbind_len len;
01536   err_t err;
01537 
01538   err = snmp_varbind_length(varbind, &len);
01539 
01540   if (err != ERR_OK) {
01541     return err;
01542   }
01543 
01544   /* check length already before adding first data because in case of GetBulk,
01545    *  data added so far is returned and therefore no partial data shall be added
01546    */
01547   if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) {
01548     return ERR_BUF;
01549   }
01550 
01551   /* 'VarBind' sequence */
01552   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len);
01553   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01554 
01555   /* VarBind OID */
01556   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len);
01557   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01558   OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len));
01559 
01560   /* VarBind value */
01561   SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len);
01562   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01563 
01564   if (len.value_value_len > 0) {
01565     if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
01566       OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t *) varbind->value, len.value_value_len));
01567     } else {
01568       switch (varbind->type) {
01569         case SNMP_ASN1_TYPE_INTEGER:
01570           OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t *) varbind->value)));
01571           break;
01572         case SNMP_ASN1_TYPE_COUNTER:
01573         case SNMP_ASN1_TYPE_GAUGE:
01574         case SNMP_ASN1_TYPE_TIMETICKS:
01575           OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t *) varbind->value)));
01576           break;
01577         case SNMP_ASN1_TYPE_OCTET_STRING:
01578         case SNMP_ASN1_TYPE_IPADDR:
01579         case SNMP_ASN1_TYPE_OPAQUE:
01580           OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t *) varbind->value, len.value_value_len));
01581           len.value_value_len = varbind->value_len;
01582           break;
01583         case SNMP_ASN1_TYPE_OBJECT_ID:
01584           OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t *) varbind->value, varbind->value_len / sizeof (u32_t)));
01585           break;
01586 #if LWIP_HAVE_INT64
01587         case SNMP_ASN1_TYPE_COUNTER64:
01588           OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, *(u64_t *) varbind->value));
01589           break;
01590 #endif
01591         default:
01592           LWIP_ASSERT("Unknown variable type", 0);
01593           break;
01594       }
01595     }
01596   }
01597 
01598   return ERR_OK;
01599 }
01600 
01601 static err_t
01602 snmp_complete_outbound_frame(struct snmp_request *request)
01603 {
01604   struct snmp_asn1_tlv tlv;
01605   u16_t frame_size;
01606   u8_t outbound_padding = 0;
01607 
01608   if (request->version == SNMP_VERSION_1) {
01609     if (request->error_status != SNMP_ERR_NOERROR) {
01610       /* map v2c error codes to v1 compliant error code (according to RFC 2089) */
01611       switch (request->error_status) {
01612         /* mapping of implementation specific "virtual" error codes
01613          * (during processing of frame we already stored them in error_status field,
01614          * so no need to check all varbinds here for those exceptions as suggested by RFC) */
01615         case SNMP_ERR_NOSUCHINSTANCE:
01616         case SNMP_ERR_NOSUCHOBJECT:
01617         case SNMP_ERR_ENDOFMIBVIEW:
01618           request->error_status = SNMP_ERR_NOSUCHNAME;
01619           break;
01620         /* mapping according to RFC */
01621         case SNMP_ERR_WRONGVALUE:
01622         case SNMP_ERR_WRONGENCODING:
01623         case SNMP_ERR_WRONGTYPE:
01624         case SNMP_ERR_WRONGLENGTH:
01625         case SNMP_ERR_INCONSISTENTVALUE:
01626           request->error_status = SNMP_ERR_BADVALUE;
01627           break;
01628         case SNMP_ERR_NOACCESS:
01629         case SNMP_ERR_NOTWRITABLE:
01630         case SNMP_ERR_NOCREATION:
01631         case SNMP_ERR_INCONSISTENTNAME:
01632         case SNMP_ERR_AUTHORIZATIONERROR:
01633           request->error_status = SNMP_ERR_NOSUCHNAME;
01634           break;
01635         case SNMP_ERR_RESOURCEUNAVAILABLE:
01636         case SNMP_ERR_COMMITFAILED:
01637         case SNMP_ERR_UNDOFAILED:
01638         default:
01639           request->error_status = SNMP_ERR_GENERROR;
01640           break;
01641       }
01642     }
01643   } else {
01644     if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
01645       /* map error codes to according to RFC 1905 (4.2.5.  The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */
01646       switch (request->error_status) {
01647         case SNMP_ERR_NOSUCHINSTANCE:
01648         case SNMP_ERR_NOSUCHOBJECT:
01649         case SNMP_ERR_ENDOFMIBVIEW:
01650           request->error_status = SNMP_ERR_NOTWRITABLE;
01651           break;
01652         default:
01653           break;
01654       }
01655     }
01656 
01657     if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
01658       /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
01659       LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
01660       return ERR_ARG;
01661     }
01662   }
01663 
01664   if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) {
01665     /* all inbound vars are returned in response without any modification for error responses and successful set requests*/
01666     struct snmp_pbuf_stream inbound_stream;
01667     OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) );
01668     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) );
01669     OF_BUILD_EXEC( snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0) );
01670   }
01671 
01672   frame_size = request->outbound_pbuf_stream.offset;
01673 
01674 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
01675   /* Calculate padding for encryption */
01676   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
01677     u8_t i;
01678     outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07;
01679     for (i = 0; i < outbound_padding; i++) {
01680       OF_BUILD_EXEC( snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0) );
01681     }
01682   }
01683 #endif
01684 
01685   /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */
01686   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()) */
01687   OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) );
01688   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
01689 
01690 #if LWIP_SNMP_V3
01691   if (request->version == SNMP_VERSION_3) {
01692     /* complete missing length in 'globalData' sequence */
01693     /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
01694     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end
01695                              - request->outbound_msg_global_data_offset - 1 - 1);
01696     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset));
01697     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01698 
01699     /* complete missing length in 'msgSecurityParameters' sequence */
01700     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end
01701                              - request->outbound_msg_security_parameters_str_offset - 1 - 1);
01702     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset));
01703     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01704 
01705     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end
01706                              - request->outbound_msg_security_parameters_seq_offset - 1 - 1);
01707     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset));
01708     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01709 
01710     /* complete missing length in scoped PDU sequence */
01711     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3);
01712     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset));
01713     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01714   }
01715 #endif
01716 
01717   /* complete missing length in 'PDU' sequence */
01718   SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3,
01719                            frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
01720   OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) );
01721   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
01722 
01723   /* process and encode final error status */
01724   if (request->error_status != 0) {
01725     u16_t len;
01726     snmp_asn1_enc_s32t_cnt(request->error_status, &len);
01727     if (len != 1) {
01728       /* error, we only reserved one byte for it */
01729       return ERR_ARG;
01730     }
01731     OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) );
01732     OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) );
01733 
01734     /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */
01735     switch (request->error_status) {
01736       case SNMP_ERR_TOOBIG:
01737         snmp_stats.outtoobigs++;
01738         break;
01739       case SNMP_ERR_NOSUCHNAME:
01740         snmp_stats.outnosuchnames++;
01741         break;
01742       case SNMP_ERR_BADVALUE:
01743         snmp_stats.outbadvalues++;
01744         break;
01745       case SNMP_ERR_GENERROR:
01746       default:
01747         snmp_stats.outgenerrs++;
01748         break;
01749     }
01750 
01751     if (request->error_status == SNMP_ERR_TOOBIG) {
01752       request->error_index = 0; /* defined by RFC 1157 */
01753     } else if (request->error_index == 0) {
01754       /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */
01755       request->error_index = request->inbound_varbind_enumerator.varbind_count;
01756     }
01757   } else {
01758     if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
01759       snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count;
01760     } else {
01761       snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count;
01762     }
01763   }
01764 
01765   /* encode final error index*/
01766   if (request->error_index != 0) {
01767     u16_t len;
01768     snmp_asn1_enc_s32t_cnt(request->error_index, &len);
01769     if (len != 1) {
01770       /* error, we only reserved one byte for it */
01771       return ERR_VAL;
01772     }
01773     OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) );
01774     OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) );
01775   }
01776 
01777   /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */
01778   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset);
01779   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()) */
01780   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
01781 
01782   /* Authenticate response */
01783 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
01784   /* Encrypt response */
01785   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
01786     u8_t key[20];
01787     snmpv3_priv_algo_t algo;
01788 
01789     /* complete missing length in PDU sequence */
01790     OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
01791     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset));
01792     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding
01793                              - request->outbound_scoped_pdu_string_offset - 1 - 3);
01794     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01795 
01796     OF_BUILD_EXEC(snmpv3_get_user((char *)request->msg_user_name, NULL, NULL, &algo, key));
01797 
01798     OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key,
01799                                request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
01800                                request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT));
01801   }
01802 
01803   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) {
01804     u8_t key[20];
01805     snmpv3_auth_algo_t algo;
01806     u8_t hmac[20];
01807 
01808     OF_BUILD_EXEC(snmpv3_get_user((char *)request->msg_user_name, &algo, key, NULL, NULL));
01809     OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream),
01810                                         request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
01811     OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
01812 
01813     MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01814     OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream,
01815                                         request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
01816     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream,
01817                                             request->outbound_msg_authentication_parameters_offset));
01818 
01819     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01820     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv));
01821     OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream,
01822                                     request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
01823   }
01824 #endif
01825 
01826   pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding);
01827 
01828   snmp_stats.outgetresponses++;
01829   snmp_stats.outpkts++;
01830 
01831   return ERR_OK;
01832 }
01833 
01834 static void
01835 snmp_execute_write_callbacks(struct snmp_request *request)
01836 {
01837   struct snmp_varbind_enumerator inbound_varbind_enumerator;
01838   struct snmp_varbind vb;
01839 
01840   snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
01841   vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
01842 
01843   while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) {
01844     snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
01845   }
01846 }
01847 
01848 
01849 /* ----------------------------------------------------------------------- */
01850 /* VarBind enumerator methods */
01851 /* ----------------------------------------------------------------------- */
01852 
01853 void
01854 snmp_vb_enumerator_init(struct snmp_varbind_enumerator *enumerator, struct pbuf *p, u16_t offset, u16_t length)
01855 {
01856   snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length);
01857   enumerator->varbind_count = 0;
01858 }
01859 
01860 #define VB_PARSE_EXEC(code)   PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
01861 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
01862 
01863 snmp_vb_enumerator_err_t
01864 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator *enumerator, struct snmp_varbind *varbind)
01865 {
01866   struct snmp_asn1_tlv tlv;
01867   u16_t  varbind_len;
01868   err_t  err;
01869 
01870   if (enumerator->pbuf_stream.length == 0) {
01871     return SNMP_VB_ENUMERATOR_ERR_EOVB;
01872   }
01873   enumerator->varbind_count++;
01874 
01875   /* decode varbind itself (parent container of a varbind) */
01876   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
01877   VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
01878   varbind_len = tlv.value_len;
01879 
01880   /* decode varbind name (object id) */
01881   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
01882   VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
01883 
01884   VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
01885   varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01886 
01887   /* decode varbind value (object id) */
01888   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
01889   VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
01890   varbind->type = tlv.type;
01891 
01892   /* shall the value be decoded ? */
01893   if (varbind->value != NULL) {
01894     switch (varbind->type) {
01895       case SNMP_ASN1_TYPE_INTEGER:
01896         VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t *)varbind->value));
01897         varbind->value_len = sizeof(s32_t);
01898         break;
01899       case SNMP_ASN1_TYPE_COUNTER:
01900       case SNMP_ASN1_TYPE_GAUGE:
01901       case SNMP_ASN1_TYPE_TIMETICKS:
01902         VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t *)varbind->value));
01903         varbind->value_len = sizeof(u32_t);
01904         break;
01905       case SNMP_ASN1_TYPE_OCTET_STRING:
01906       case SNMP_ASN1_TYPE_OPAQUE:
01907         err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t *)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
01908         if (err == ERR_MEM) {
01909           return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
01910         }
01911         VB_PARSE_ASSERT(err == ERR_OK);
01912         break;
01913       case SNMP_ASN1_TYPE_NULL:
01914         varbind->value_len = 0;
01915         break;
01916       case SNMP_ASN1_TYPE_OBJECT_ID:
01917         /* misuse tlv.length_len as OID_length transporter */
01918         err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t *)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
01919         if (err == ERR_MEM) {
01920           return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
01921         }
01922         VB_PARSE_ASSERT(err == ERR_OK);
01923         varbind->value_len = tlv.length_len * sizeof(u32_t);
01924         break;
01925       case SNMP_ASN1_TYPE_IPADDR:
01926         if (tlv.value_len == 4) {
01927           /* must be exactly 4 octets! */
01928           VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t *)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
01929         } else {
01930           VB_PARSE_ASSERT(0);
01931         }
01932         break;
01933 #if LWIP_HAVE_INT64
01934       case SNMP_ASN1_TYPE_COUNTER64:
01935         VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u64_t *)varbind->value));
01936         varbind->value_len = sizeof(u64_t);
01937         break;
01938 #endif
01939       default:
01940         VB_PARSE_ASSERT(0);
01941         break;
01942     }
01943   } else {
01944     snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
01945     varbind->value_len = tlv.value_len;
01946   }
01947 
01948   return SNMP_VB_ENUMERATOR_ERR_OK;
01949 }
01950 
01951 #endif /* LWIP_SNMP */