ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

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_SNMPV3_INCLUDE_ENGINE
00052 #include LWIP_SNMPV3_INCLUDE_ENGINE
00053 #endif
00054 #endif
00055 
00056 #include <string.h>
00057 
00058 /* public (non-static) constants */
00059 /** SNMP community string */
00060 const char *snmp_community = SNMP_COMMUNITY;
00061 /** SNMP community string for write access */
00062 const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
00063 /** SNMP community string for sending traps */
00064 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
00065 
00066 snmp_write_callback_fct snmp_write_callback     = NULL;
00067 void*                   snmp_write_callback_arg = NULL;
00068 
00069 /**
00070  * @ingroup snmp_core
00071  * Returns current SNMP community string.
00072  * @return current SNMP community string
00073  */
00074 const char *
00075 snmp_get_community(void)
00076 {
00077   return snmp_community;
00078 }
00079 
00080 /**
00081  * @ingroup snmp_core
00082  * Sets SNMP community string.
00083  * The string itself (its storage) must be valid throughout the whole life of
00084  * program (or until it is changed to sth else).
00085  *
00086  * @param community is a pointer to new community string
00087  */
00088 void
00089 snmp_set_community(const char * const community)
00090 {
00091   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
00092   snmp_community = community;
00093 }
00094 
00095 /**
00096  * @ingroup snmp_core
00097  * Returns current SNMP write-access community string.
00098  * @return current SNMP write-access community string
00099  */
00100 const char *
00101 snmp_get_community_write(void)
00102 {
00103   return snmp_community_write;
00104 }
00105 
00106 /**
00107  * @ingroup snmp_traps
00108  * Returns current SNMP community string used for sending traps.
00109  * @return current SNMP community string used for sending traps
00110  */
00111 const char *
00112 snmp_get_community_trap(void)
00113 {
00114   return snmp_community_trap;
00115 }
00116 
00117 /**
00118  * @ingroup snmp_core
00119  * Sets SNMP community string for write-access.
00120  * The string itself (its storage) must be valid throughout the whole life of
00121  * program (or until it is changed to sth else).
00122  *
00123  * @param community is a pointer to new write-access community string
00124  */
00125 void
00126 snmp_set_community_write(const char * const community)
00127 {
00128   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
00129   snmp_community_write = community;
00130 }
00131 
00132 /**
00133  * @ingroup snmp_traps
00134  * Sets SNMP community string used for sending traps.
00135  * The string itself (its storage) must be valid throughout the whole life of
00136  * program (or until it is changed to sth else).
00137  *
00138  * @param community is a pointer to new trap community string
00139  */
00140 void
00141 snmp_set_community_trap(const char * const community)
00142 {
00143   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
00144   snmp_community_trap = community;
00145 }
00146 
00147 /**
00148  * @ingroup snmp_core
00149  * Callback fired on every successful write access
00150  */
00151 void 
00152 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg)
00153 {
00154   snmp_write_callback     = write_callback;
00155   snmp_write_callback_arg = callback_arg;
00156 }
00157 
00158 /* ----------------------------------------------------------------------- */
00159 /* forward declarations */
00160 /* ----------------------------------------------------------------------- */
00161 
00162 static err_t snmp_process_get_request(struct snmp_request *request);
00163 static err_t snmp_process_getnext_request(struct snmp_request *request);
00164 static err_t snmp_process_getbulk_request(struct snmp_request *request);
00165 static err_t snmp_process_set_request(struct snmp_request *request);
00166 
00167 static err_t snmp_parse_inbound_frame(struct snmp_request *request);
00168 static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
00169 static err_t snmp_complete_outbound_frame(struct snmp_request *request);
00170 static void snmp_execute_write_callbacks(struct snmp_request *request);
00171 
00172 
00173 /* ----------------------------------------------------------------------- */
00174 /* implementation */
00175 /* ----------------------------------------------------------------------- */
00176 
00177 void
00178 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port)
00179 {
00180   err_t err;
00181   struct snmp_request request;
00182    
00183   memset(&request, 0, sizeof(request));
00184   request.handle       = handle;
00185   request.source_ip    = source_ip;
00186   request.source_port  = port;
00187   request.inbound_pbuf = p;
00188 
00189   snmp_stats.inpkts++;
00190 
00191   err = snmp_parse_inbound_frame(&request);
00192   if (err == ERR_OK) {
00193     err = snmp_prepare_outbound_frame(&request);
00194     if (err == ERR_OK) {
00195 
00196       if (request.error_status == SNMP_ERR_NOERROR) {
00197         /* only process frame if we do not already have an error to return (e.g. all readonly) */
00198         if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) {
00199           err = snmp_process_get_request(&request);
00200         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) {
00201           err = snmp_process_getnext_request(&request);
00202         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
00203           err = snmp_process_getbulk_request(&request);
00204         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
00205           err = snmp_process_set_request(&request);
00206         }
00207       }
00208 
00209       if (err == ERR_OK) {
00210         err = snmp_complete_outbound_frame(&request);
00211       
00212         if (err == ERR_OK) {
00213           err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port);
00214 
00215           if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) 
00216             && (request.error_status == SNMP_ERR_NOERROR) 
00217             && (snmp_write_callback != NULL)) {
00218             /* raise write notification for all written objects */
00219             snmp_execute_write_callbacks(&request);
00220           }
00221         }
00222       }
00223     }
00224   
00225     if (request.outbound_pbuf != NULL) {
00226       pbuf_free(request.outbound_pbuf);
00227     }
00228   }
00229 }
00230 
00231 static u8_t
00232 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg)
00233 {
00234   if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) {
00235     return SNMP_ERR_NOSUCHINSTANCE;
00236   }
00237 
00238   if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) {
00239     /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */
00240     return SNMP_ERR_NOSUCHINSTANCE;
00241   }
00242 
00243   return SNMP_ERR_NOERROR;
00244 }
00245 
00246 static void 
00247 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
00248 {
00249   err_t err;
00250   struct snmp_node_instance node_instance;
00251   memset(&node_instance, 0, sizeof(node_instance));
00252 
00253   if (get_next) {
00254     struct snmp_obj_id result_oid;
00255     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);
00256 
00257     if (request->error_status == SNMP_ERR_NOERROR) {
00258       snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
00259     }
00260   } else {
00261     request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);
00262 
00263     if (request->error_status == SNMP_ERR_NOERROR) {
00264       /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
00265       request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);
00266 
00267       if (request->error_status != SNMP_ERR_NOERROR) {
00268         if (node_instance.release_instance != NULL) {
00269           node_instance.release_instance(&node_instance);
00270         }
00271       }
00272     }
00273   }
00274 
00275   if (request->error_status != SNMP_ERR_NOERROR)
00276   {
00277     if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
00278       if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) {
00279         /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
00280         vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
00281         vb->value_len = 0;
00282 
00283         err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb);
00284         if (err == ERR_OK) {
00285           /* we stored the exception in varbind -> go on */
00286           request->error_status = SNMP_ERR_NOERROR;
00287         } else if (err == ERR_BUF) {
00288           request->error_status = SNMP_ERR_TOOBIG;
00289         } else {
00290           request->error_status = SNMP_ERR_GENERROR;
00291         }
00292       }
00293     } else {
00294       /* according to RFC 1157/1905, all other errors only return genError */
00295       request->error_status = SNMP_ERR_GENERROR;
00296     }
00297   } else {
00298     s16_t len = node_instance.get_value(&node_instance, vb->value);
00299     vb->type = node_instance.asn1_type;
00300 
00301     if(len >= 0) {
00302       vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */
00303 
00304       LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);
00305       err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb);
00306 
00307       if (err == ERR_BUF) {
00308         request->error_status = SNMP_ERR_TOOBIG;
00309       } else if (err != ERR_OK) {
00310         request->error_status = SNMP_ERR_GENERROR;
00311       }
00312     } else {
00313       request->error_status = SNMP_ERR_GENERROR;
00314     }
00315 
00316     if (node_instance.release_instance != NULL) {
00317       node_instance.release_instance(&node_instance);
00318     }
00319   }
00320 }
00321 
00322 
00323 /**
00324  * Service an internal or external event for SNMP GET.
00325  *
00326  * @param msg_ps points to the associated message process state
00327  */
00328 static err_t
00329 snmp_process_get_request(struct snmp_request *request)
00330 {
00331   snmp_vb_enumerator_err_t err;
00332   struct snmp_varbind vb;
00333   vb.value = request->value_buffer;
00334 
00335   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n"));
00336 
00337   while (request->error_status == SNMP_ERR_NOERROR) {
00338     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00339     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00340       if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
00341         snmp_process_varbind(request, &vb, 0);
00342       } else {
00343         request->error_status = SNMP_ERR_GENERROR;
00344       }
00345     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00346       /* no more varbinds in request */
00347       break;
00348     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00349       /* malformed ASN.1, don't answer */
00350       return ERR_ARG;
00351     } else {
00352       request->error_status = SNMP_ERR_GENERROR;
00353     }
00354   }
00355 
00356   return ERR_OK;
00357 }
00358 
00359 /**
00360  * Service an internal or external event for SNMP GET.
00361  *
00362  * @param msg_ps points to the associated message process state
00363  */
00364 static err_t
00365 snmp_process_getnext_request(struct snmp_request *request)
00366 {
00367   snmp_vb_enumerator_err_t err;
00368   struct snmp_varbind vb;
00369   vb.value = request->value_buffer;
00370 
00371   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n"));
00372 
00373   while (request->error_status == SNMP_ERR_NOERROR) {
00374     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00375     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00376       if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
00377         snmp_process_varbind(request, &vb, 1);
00378       } else {
00379         request->error_status = SNMP_ERR_GENERROR;
00380       }
00381     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00382       /* no more varbinds in request */
00383       break;
00384     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00385       /* malformed ASN.1, don't answer */
00386       return ERR_ARG;
00387     } else {
00388       request->error_status = SNMP_ERR_GENERROR;
00389     }
00390   }
00391   
00392   return ERR_OK;
00393 }
00394 
00395 /**
00396  * Service an internal or external event for SNMP GETBULKT.
00397  *
00398  * @param msg_ps points to the associated message process state
00399  */
00400 static err_t
00401 snmp_process_getbulk_request(struct snmp_request *request)
00402 {
00403   snmp_vb_enumerator_err_t err;
00404   s32_t non_repeaters     = request->non_repeaters;
00405   s32_t repetitions;
00406   u16_t repetition_offset = 0;
00407   struct snmp_varbind_enumerator repetition_varbind_enumerator;
00408   struct snmp_varbind vb;
00409   vb.value = request->value_buffer;
00410 
00411   if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) {
00412     repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS);
00413   } else {
00414     repetitions = request->max_repetitions;
00415   }
00416 
00417   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n"));
00418 
00419   /* process non repeaters and first repetition */
00420   while (request->error_status == SNMP_ERR_NOERROR) {
00421     if (non_repeaters == 0) {
00422       repetition_offset = request->outbound_pbuf_stream.offset;
00423 
00424       if (repetitions == 0) {
00425         /* do not resolve repeaters when repetitions is set to 0 */
00426         break;
00427       }
00428       repetitions--;
00429     }
00430 
00431     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00432     if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00433       /* no more varbinds in request */
00434       break;
00435     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00436       /* malformed ASN.1, don't answer */
00437       return ERR_ARG;
00438     } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) {
00439       request->error_status = SNMP_ERR_GENERROR;
00440     } else {
00441       snmp_process_varbind(request, &vb, 1);
00442       non_repeaters--;
00443     }
00444   }
00445 
00446   /* process repetitions > 1 */
00447   while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) {
00448 
00449     u8_t all_endofmibview = 1;
00450     
00451     snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset);
00452     repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */
00453 
00454     while (request->error_status == SNMP_ERR_NOERROR) {
00455       vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */
00456       err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb);
00457       if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00458         vb.value = request->value_buffer;
00459         snmp_process_varbind(request, &vb, 1);
00460 
00461         if (request->error_status != SNMP_ERR_NOERROR) {
00462           /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */
00463           request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
00464         } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) {
00465           all_endofmibview = 0;
00466         }
00467       } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00468         /* no more varbinds in request */
00469         break;
00470       } else {
00471         LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!"));
00472         request->error_status = SNMP_ERR_GENERROR;
00473         request->error_index  = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
00474       }
00475     }
00476 
00477     if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) {
00478       /* stop when all varbinds in a loop return EndOfMibView */
00479       break;
00480     }
00481     
00482     repetitions--;
00483   }
00484 
00485   if (request->error_status == SNMP_ERR_TOOBIG) {
00486     /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */
00487     request->error_status = SNMP_ERR_NOERROR;
00488   }
00489 
00490   return ERR_OK;
00491 }
00492 
00493 /**
00494  * Service an internal or external event for SNMP SET.
00495  *
00496  * @param msg_ps points to the associated message process state
00497  */
00498 static err_t
00499 snmp_process_set_request(struct snmp_request *request)
00500 {
00501   snmp_vb_enumerator_err_t err;
00502   struct snmp_varbind vb;
00503   vb.value = request->value_buffer;
00504 
00505   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n"));
00506 
00507   /* perform set test on all objects */
00508   while (request->error_status == SNMP_ERR_NOERROR) {
00509     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00510     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00511       struct snmp_node_instance node_instance;
00512       memset(&node_instance, 0, sizeof(node_instance));
00513       
00514       request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
00515       if (request->error_status == SNMP_ERR_NOERROR)
00516       {
00517         if (node_instance.asn1_type != vb.type) {
00518           request->error_status = SNMP_ERR_WRONGTYPE;
00519         } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
00520           request->error_status = SNMP_ERR_NOTWRITABLE;
00521         } else {
00522           if (node_instance.set_test != NULL) {
00523             request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value);
00524           }
00525         }
00526 
00527         if (node_instance.release_instance != NULL) {
00528           node_instance.release_instance(&node_instance);
00529         }
00530       }
00531     }
00532     else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00533       /* no more varbinds in request */
00534       break;
00535     } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
00536       request->error_status = SNMP_ERR_WRONGLENGTH;
00537     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
00538       /* malformed ASN.1, don't answer */
00539       return ERR_ARG;
00540     } else {
00541       request->error_status = SNMP_ERR_GENERROR;
00542     }
00543   }
00544 
00545   /* perform real set operation on all objects */
00546   if (request->error_status == SNMP_ERR_NOERROR) {
00547     snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
00548     while (request->error_status == SNMP_ERR_NOERROR) {
00549       err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
00550       if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
00551         struct snmp_node_instance node_instance;
00552         memset(&node_instance, 0, sizeof(node_instance));
00553         request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
00554         if (request->error_status == SNMP_ERR_NOERROR)
00555         {
00556           if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR)
00557           {
00558             if (request->inbound_varbind_enumerator.varbind_count == 1) {
00559               request->error_status = SNMP_ERR_COMMITFAILED;
00560             } else {
00561               /* we cannot undo the set operations done so far */
00562               request->error_status = SNMP_ERR_UNDOFAILED;
00563             }
00564           }
00565 
00566           if (node_instance.release_instance != NULL) {
00567             node_instance.release_instance(&node_instance);
00568           }
00569         }
00570       } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
00571         /* no more varbinds in request */
00572         break;
00573       } else {
00574         /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */
00575         request->error_status = SNMP_ERR_GENERROR;
00576       }
00577     }
00578   }
00579 
00580   return ERR_OK;
00581 }
00582 
00583 #define PARSE_EXEC(code, retValue) \
00584   if ((code) != ERR_OK) { \
00585     LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \
00586     snmp_stats.inasnparseerrs++; \
00587     return retValue; \
00588   }
00589 
00590 #define PARSE_ASSERT(cond, retValue) \
00591   if (!(cond)) { \
00592     LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \
00593     snmp_stats.inasnparseerrs++; \
00594     return retValue; \
00595   }
00596 
00597 #define BUILD_EXEC(code, retValue) \
00598   if ((code) != ERR_OK) { \
00599     LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \
00600     return retValue; \
00601   }
00602 
00603 #define IF_PARSE_EXEC(code)   PARSE_EXEC(code, ERR_ARG)
00604 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG)
00605 
00606 /**
00607  * Checks and decodes incoming SNMP message header, logs header errors.
00608  *
00609  * @param request points to the current message request state return
00610  * @return
00611  * - ERR_OK SNMP header is sane and accepted
00612  * - ERR_VAL SNMP header is either malformed or rejected
00613  */
00614 static err_t
00615 snmp_parse_inbound_frame(struct snmp_request *request)
00616 {
00617   struct snmp_pbuf_stream pbuf_stream;
00618   struct snmp_asn1_tlv tlv;
00619   s32_t parent_tlv_value_len;
00620   s32_t s32_value;
00621   err_t err;
00622 
00623   IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
00624   
00625   /* decode main container consisting of version, community and PDU */
00626   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00627   IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
00628   parent_tlv_value_len = tlv.value_len;
00629 
00630   /* decode version */
00631   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00632   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00633   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00634   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00635   
00636   IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00637   if ((s32_value != SNMP_VERSION_1) &&
00638       (s32_value != SNMP_VERSION_2c)
00639 #if LWIP_SNMP_V3
00640       && (s32_value != SNMP_VERSION_3)
00641 #endif
00642      )
00643   {
00644     /* unsupported SNMP version */
00645     snmp_stats.inbadversions++;
00646     return ERR_ARG;
00647   }
00648   request->version = (u8_t)s32_value;
00649 
00650 #if LWIP_SNMP_V3
00651   if (request->version == SNMP_VERSION_3) {
00652     u16_t u16_value;
00653 
00654     /* SNMPv3 doesn't use communities */
00655     /* @todo: Differentiate read/write access */
00656     strcpy((char*)request->community, snmp_community);
00657     request->community_strlen = strlen(snmp_community);
00658 
00659     /* RFC3414 globalData */
00660     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00661     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
00662     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00663     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00664 
00665     /* decode msgID */
00666     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00667     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00668     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00669     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00670 
00671     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00672     request->msg_id = s32_value;
00673 
00674     /* decode msgMaxSize */
00675     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00676     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00677     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00678     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00679 
00680     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00681     request->msg_max_size = s32_value;
00682 
00683     /* decode msgFlags */
00684     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00685     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00686     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00687     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00688 
00689     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00690     request->msg_flags = s32_value;
00691 
00692     /* decode msgSecurityModel */
00693     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00694     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00695     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00696     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00697 
00698     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00699     request->msg_security_model = s32_value;
00700 
00701     /* RFC3414 msgSecurityParameters
00702      * The User-based Security Model defines the contents of the OCTET
00703      * STRING as a SEQUENCE.
00704      *
00705      * We skip the protective dummy OCTET STRING header
00706      * to access the SEQUENCE header.
00707      */
00708     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00709     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00710     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00711     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00712 
00713     /* msgSecurityParameters SEQUENCE header */
00714     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00715     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
00716     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00717     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00718 
00719     /* decode msgAuthoritativeEngineID */
00720     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00721     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00722     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00723     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00724 
00725     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id,
00726         &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
00727     request->msg_authoritative_engine_id_len = u16_value;
00728 
00729     /* msgAuthoritativeEngineBoots */
00730     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00731     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00732     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00733     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00734     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots));
00735 
00736     /* msgAuthoritativeEngineTime */
00737     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00738     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00739     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00740     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00741     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time));
00742     /* @todo: Implement time window checking */
00743 
00744     /* msgUserName */
00745     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00746     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00747     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00748     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00749 
00750     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name,
00751         &u16_value, SNMP_V3_MAX_USER_LENGTH));
00752     request->msg_user_name_len = u16_value;
00753     /* @todo: Implement unknown user error response */
00754     IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, NULL, NULL));
00755 
00756     /* msgAuthenticationParameters */
00757     memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
00758     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00759     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00760     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00761     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00762     /* Remember position */
00763     u16_t inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
00764     LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset);
00765     /* Read auth parameters */
00766     IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH);
00767     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters,
00768         &u16_value, tlv.value_len));
00769 
00770 #if LWIP_SNMP_V3_CRYPTO
00771     if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
00772       /* Rewind stream */
00773       IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
00774       IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset));
00775       /* Set auth parameters to zero for verification */
00776       const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 };
00777       IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len));
00778 
00779       /* Verify authentication */
00780       u8_t key[20];
00781       u8_t algo;
00782       u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)];
00783       struct snmp_pbuf_stream auth_stream;
00784       IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
00785 
00786       IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, &algo, key, NULL, NULL));
00787       IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac));
00788       /* @todo: Implement error response */
00789       IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
00790     }
00791 #else
00792     /* Ungraceful exit if we encounter cryptography and don't support it.
00793      * @todo: Implement error response
00794      */
00795     IF_PARSE_ASSERT(!(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)));
00796 #endif
00797 
00798     /* msgPrivacyParameters */
00799     memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
00800     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00801     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00802     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00803     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00804 
00805     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters,
00806         &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
00807 
00808 #if LWIP_SNMP_V3_CRYPTO
00809     /* Decrypt message */
00810     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
00811       u8_t key[20];
00812       u8_t algo;
00813 
00814       IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00815       IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00816       parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00817       IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00818 
00819       IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, &algo, key));
00820       IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key,
00821           request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
00822           request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT));
00823     }
00824 #endif
00825 
00826     /* Scoped PDU
00827      * Encryption context
00828      */
00829     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00830     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
00831     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
00832     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00833 
00834     /* contextEngineID */
00835     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00836     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00837     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00838     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00839 
00840     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id,
00841         &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
00842     request->context_engine_id_len = u16_value;
00843 
00844     /* contextName */
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_raw(&pbuf_stream, tlv.value_len, request->context_name,
00851         &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
00852     request->context_name_len = u16_value;
00853   } else
00854 #endif
00855   {
00856   /* decode community */
00857   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00858   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
00859   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00860   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00861 
00862   err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
00863   if (err == ERR_MEM) {
00864     /* community string does not fit in our buffer -> its too long -> its invalid */
00865     request->community_strlen = 0;
00866     snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
00867   } else {
00868     IF_PARSE_ASSERT(err == ERR_OK);
00869   }
00870   /* add zero terminator */
00871   request->community[request->community_strlen] = 0;
00872   }
00873 
00874   /* decode PDU type (next container level) */
00875   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00876   IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length);
00877   request->inbound_padding_len = pbuf_stream.length - tlv.value_len;
00878   parent_tlv_value_len = tlv.value_len;
00879 
00880   /* validate PDU type */
00881   switch(tlv.type) {
00882     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
00883       /* GetRequest PDU */
00884       snmp_stats.ingetrequests++;
00885       break;
00886     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
00887       /* GetNextRequest PDU */
00888       snmp_stats.ingetnexts++;
00889       break;
00890     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
00891       /* GetBulkRequest PDU */
00892       if (request->version < SNMP_VERSION_2c) {
00893         /* RFC2089: invalid, drop packet */
00894         return ERR_ARG;
00895       }
00896       break;
00897     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
00898       /* SetRequest PDU */
00899       snmp_stats.insetrequests++;
00900       break;
00901     default:
00902       /* unsupported input PDU for this agent (no parse error) */
00903       LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
00904       return ERR_ARG;
00905       break;
00906   }
00907   request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;
00908 
00909   /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
00910   if (request->community_strlen == 0) {
00911     /* community string was too long or really empty*/
00912     snmp_stats.inbadcommunitynames++;
00913     snmp_authfail_trap();
00914     return ERR_ARG;
00915   } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
00916     if (strnlen(snmp_community_write, SNMP_MAX_COMMUNITY_STR_LEN) == 0) {
00917       /* our write community is empty, that means all our objects are readonly */
00918       request->error_status = SNMP_ERR_NOTWRITABLE;
00919       request->error_index  = 1;
00920     } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
00921       /* community name does not match */
00922       snmp_stats.inbadcommunitynames++;
00923       snmp_authfail_trap();
00924       return ERR_ARG;
00925     }
00926   } else { 
00927     if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
00928       /* community name does not match */
00929       snmp_stats.inbadcommunitynames++;
00930       snmp_authfail_trap();
00931       return ERR_ARG;
00932     }
00933   }
00934   
00935   /* decode request ID */
00936   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00937   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00938   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00939   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00940   
00941   IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));
00942 
00943   /* decode error status / non-repeaters */
00944   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00945   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00946   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00947   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00948 
00949   if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
00950     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
00951     if (request->non_repeaters < 0) {
00952       /* RFC 1905, 4.2.3 */
00953       request->non_repeaters = 0;
00954     }
00955   } else {
00956     /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
00957     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
00958     IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
00959   }
00960 
00961   /* decode error index / max-repetitions */
00962   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00963   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
00964   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
00965   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
00966 
00967   if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
00968     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
00969     if (request->max_repetitions < 0) {
00970       /* RFC 1905, 4.2.3 */
00971       request->max_repetitions = 0;
00972     }
00973   } else {
00974     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
00975     IF_PARSE_ASSERT(s32_value == 0);
00976   }
00977 
00978   /* decode varbind-list type (next container level) */
00979   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
00980   IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length));
00981   
00982   request->inbound_varbind_offset = pbuf_stream.offset;
00983   request->inbound_varbind_len    = pbuf_stream.length - request->inbound_padding_len;
00984   snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
00985 
00986   return ERR_OK;
00987 }
00988 
00989 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
00990 
00991 static err_t
00992 snmp_prepare_outbound_frame(struct snmp_request *request)
00993 {
00994   struct snmp_asn1_tlv tlv;
00995   struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream);
00996 
00997   /* try allocating pbuf(s) for maximum response size */
00998   request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM);
00999   if (request->outbound_pbuf == NULL) {
01000     return ERR_MEM;
01001   }
01002 
01003   snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len);
01004 
01005   /* 'Message' sequence */
01006   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
01007   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01008 
01009   /* version */
01010   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01011   snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len);
01012   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01013   OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) );
01014 
01015 #if LWIP_SNMP_V3
01016   if (request->version < SNMP_VERSION_3) {
01017 #endif
01018   /* community */
01019   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen);
01020   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01021   OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
01022 #if LWIP_SNMP_V3
01023   } else {
01024     const char* id;
01025 
01026     /* globalData */
01027     request->outbound_msg_global_data_offset = pbuf_stream->offset;
01028     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
01029     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01030 
01031     /* msgID */
01032     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01033     snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len);
01034     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01035     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id));
01036 
01037     /* msgMaxSize */
01038     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01039     snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len);
01040     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01041     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size));
01042 
01043     /* msgFlags */
01044     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1);
01045     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01046     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1));
01047 
01048     /* msgSecurityModel */
01049     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01050     snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len);
01051     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01052     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model));
01053 
01054     /* end of msgGlobalData */
01055     request->outbound_msg_global_data_end = pbuf_stream->offset;
01056 
01057     /* msgSecurityParameters */
01058     request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset;
01059     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0);
01060     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01061 
01062     request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset;
01063     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
01064     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01065 
01066     /* msgAuthoritativeEngineID */
01067     snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
01068     memcpy(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
01069     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len);
01070     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01071     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len));
01072 
01073     request->msg_authoritative_engine_time = snmpv3_get_engine_time();
01074     request->msg_authoritative_engine_boots = snmpv3_get_engine_boots();
01075 
01076     /* msgAuthoritativeEngineBoots */
01077     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01078     snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len);
01079     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01080     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots));
01081 
01082     /* msgAuthoritativeEngineTime */
01083     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01084     snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len);
01085     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01086     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time));
01087 
01088     /* msgUserName */
01089     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len);
01090     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01091     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len));
01092 
01093 #if LWIP_SNMP_V3_CRYPTO
01094     /* msgAuthenticationParameters */
01095     if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
01096       memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01097       request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset;
01098       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01099       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01100       OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
01101     } else
01102 #endif
01103     {
01104       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
01105       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01106     }
01107 
01108 #if LWIP_SNMP_V3_CRYPTO
01109     /* msgPrivacyParameters */
01110     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
01111       snmpv3_build_priv_param(request->msg_privacy_parameters);
01112 
01113       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
01114       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01115       OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
01116     } else
01117 #endif
01118     {
01119       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
01120       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01121     }
01122 
01123     /* End of msgSecurityParameters, so we can calculate the length of this sequence later */
01124     request->outbound_msg_security_parameters_end = pbuf_stream->offset;
01125 
01126 #if LWIP_SNMP_V3_CRYPTO
01127     /* For encryption we have to encapsulate the payload in an octet string */
01128     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
01129       request->outbound_scoped_pdu_string_offset = pbuf_stream->offset;
01130       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0);
01131       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01132     }
01133 #endif
01134     /* Scoped PDU
01135      * Encryption context
01136      */
01137     request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset;
01138     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
01139     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01140 
01141     /* contextEngineID */
01142     snmpv3_get_engine_id(&id, &request->context_engine_id_len);
01143     memcpy(request->context_engine_id, id, request->context_engine_id_len);
01144     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len);
01145     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01146     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
01147 
01148     /* contextName */
01149     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len);
01150     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01151     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len));
01152   }
01153 #endif
01154 
01155   /* 'PDU' sequence */
01156   request->outbound_pdu_offset = pbuf_stream->offset;
01157   SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0);
01158   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01159 
01160   /* request ID */
01161   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
01162   snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len);
01163   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01164   OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) );
01165 
01166   /* error status */
01167   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01168   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01169   request->outbound_error_status_offset = pbuf_stream->offset;
01170   OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
01171 
01172   /* error index */
01173   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
01174   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01175   request->outbound_error_index_offset = pbuf_stream->offset;
01176   OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
01177 
01178   /* 'VarBindList' sequence */
01179   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
01180   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
01181 
01182   request->outbound_varbind_offset = pbuf_stream->offset;
01183 
01184   return ERR_OK;
01185 }
01186 
01187 /** Calculate the length of a varbind list */
01188 err_t
01189 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len)
01190 {
01191   /* calculate required lengths */
01192   snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len);
01193   snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len);
01194 
01195   if (varbind->value_len == 0) {
01196     len->value_value_len = 0;
01197   } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
01198     len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA);
01199   } else {
01200     switch (varbind->type) {
01201       case SNMP_ASN1_TYPE_INTEGER:
01202         if (varbind->value_len != sizeof (s32_t)) {
01203           return ERR_VAL;
01204         }
01205         snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len);
01206         break;
01207       case SNMP_ASN1_TYPE_COUNTER:
01208       case SNMP_ASN1_TYPE_GAUGE:
01209       case SNMP_ASN1_TYPE_TIMETICKS:
01210         if (varbind->value_len != sizeof (u32_t)) {
01211           return ERR_VAL;
01212         }
01213         snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len);
01214         break;
01215       case SNMP_ASN1_TYPE_OCTET_STRING:
01216       case SNMP_ASN1_TYPE_IPADDR:
01217       case SNMP_ASN1_TYPE_OPAQUE:
01218         len->value_value_len = varbind->value_len;
01219         break;
01220       case SNMP_ASN1_TYPE_NULL:
01221         if (varbind->value_len != 0) {
01222           return ERR_VAL;
01223         }
01224         len->value_value_len = 0;
01225         break;
01226       case SNMP_ASN1_TYPE_OBJECT_ID:
01227         if ((varbind->value_len & 0x03) != 0) {
01228           return ERR_VAL;
01229         }
01230         snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len);
01231         break;
01232       case SNMP_ASN1_TYPE_COUNTER64:
01233         if (varbind->value_len != (2 * sizeof (u32_t))) {
01234           return ERR_VAL;
01235         }
01236         snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len);
01237         break;
01238       default:
01239         /* unsupported type */
01240         return ERR_VAL;
01241     }
01242   }
01243   snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len);
01244 
01245   len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len;
01246   snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len);
01247 
01248   return ERR_OK;
01249 }
01250 
01251 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
01252 
01253 err_t
01254 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind)
01255 {
01256   struct snmp_asn1_tlv tlv;
01257   struct snmp_varbind_len len;
01258   err_t err;
01259 
01260   err = snmp_varbind_length(varbind, &len);
01261 
01262   if (err != ERR_OK) {
01263     return err;
01264   }
01265 
01266   /* check length already before adding first data because in case of GetBulk,
01267    *  data added so far is returned and therefore no partial data shall be added
01268    */
01269   if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) {
01270     return ERR_BUF;
01271   }
01272 
01273   /* 'VarBind' sequence */
01274   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len);
01275   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01276 
01277   /* VarBind OID */
01278   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len);
01279   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01280   OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len));
01281 
01282   /* VarBind value */
01283   SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len);
01284   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
01285 
01286   if (len.value_value_len > 0) {
01287     if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
01288       OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
01289     } else {
01290       switch (varbind->type) {
01291         case SNMP_ASN1_TYPE_INTEGER:
01292           OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value)));
01293           break;
01294         case SNMP_ASN1_TYPE_COUNTER:
01295         case SNMP_ASN1_TYPE_GAUGE:
01296         case SNMP_ASN1_TYPE_TIMETICKS:
01297           OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value)));
01298           break;
01299         case SNMP_ASN1_TYPE_OCTET_STRING:
01300         case SNMP_ASN1_TYPE_IPADDR:
01301         case SNMP_ASN1_TYPE_OPAQUE:
01302           OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
01303           len.value_value_len = varbind->value_len;
01304           break;
01305         case SNMP_ASN1_TYPE_OBJECT_ID:
01306           OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t)));
01307           break;
01308         case SNMP_ASN1_TYPE_COUNTER64:
01309           OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value));
01310           break;
01311         default:
01312           LWIP_ASSERT("Unknown variable type", 0);
01313           break;
01314       }
01315     }
01316   }
01317 
01318   return ERR_OK;
01319 }
01320 
01321 static err_t
01322 snmp_complete_outbound_frame(struct snmp_request *request)
01323 {
01324   struct snmp_asn1_tlv tlv;
01325   u16_t frame_size;
01326   u8_t outbound_padding = 0;
01327 
01328   if (request->version == SNMP_VERSION_1) {
01329     if (request->error_status != SNMP_ERR_NOERROR) {
01330       /* map v2c error codes to v1 compliant error code (according to RFC 2089) */
01331       switch (request->error_status) {
01332         /* mapping of implementation specific "virtual" error codes 
01333          * (during processing of frame we already stored them in error_status field, 
01334          * so no need to check all varbinds here for those exceptions as suggested by RFC) */
01335         case SNMP_ERR_NOSUCHINSTANCE:
01336         case SNMP_ERR_NOSUCHOBJECT:
01337         case SNMP_ERR_ENDOFMIBVIEW:
01338           request->error_status = SNMP_ERR_NOSUCHNAME;
01339           break;
01340         /* mapping according to RFC */
01341         case SNMP_ERR_WRONGVALUE:
01342         case SNMP_ERR_WRONGENCODING:
01343         case SNMP_ERR_WRONGTYPE:
01344         case SNMP_ERR_WRONGLENGTH:
01345         case SNMP_ERR_INCONSISTENTVALUE:
01346           request->error_status = SNMP_ERR_BADVALUE;
01347           break;
01348         case SNMP_ERR_NOACCESS:
01349         case SNMP_ERR_NOTWRITABLE:
01350         case SNMP_ERR_NOCREATION:
01351         case SNMP_ERR_INCONSISTENTNAME:
01352         case SNMP_ERR_AUTHORIZATIONERROR:
01353           request->error_status = SNMP_ERR_NOSUCHNAME;
01354           break;
01355         case SNMP_ERR_RESOURCEUNAVAILABLE:
01356         case SNMP_ERR_COMMITFAILED:
01357         case SNMP_ERR_UNDOFAILED:
01358         default:
01359           request->error_status = SNMP_ERR_GENERROR;
01360           break;
01361        }
01362     }
01363   } else {
01364     if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
01365       /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
01366       LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
01367       return ERR_ARG;
01368     }
01369   }
01370 
01371   if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) {
01372     /* all inbound vars are returned in response without any modification for error responses and successful set requests*/
01373     struct snmp_pbuf_stream inbound_stream;
01374     OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) );
01375     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) );
01376     snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0);
01377   }
01378 
01379   frame_size = request->outbound_pbuf_stream.offset;
01380 
01381 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
01382   /* Calculate padding for encryption */
01383   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
01384     u8_t i;
01385     outbound_padding = (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x03);
01386     for (i = 0; i < outbound_padding; i++) {
01387       snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0);
01388     }
01389   }
01390 #endif
01391 
01392   /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */
01393   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()) */
01394   OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) );
01395   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
01396 
01397 #if LWIP_SNMP_V3
01398   if (request->version == SNMP_VERSION_3) {
01399     /* complete missing length in 'globalData' sequence */
01400     /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
01401     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end
01402         - request->outbound_msg_global_data_offset - 1 - 1);
01403     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset));
01404     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01405 
01406     /* complete missing length in 'msgSecurityParameters' sequence */
01407     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end
01408         - request->outbound_msg_security_parameters_str_offset - 1 - 1);
01409     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset));
01410     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01411 
01412     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end
01413         - request->outbound_msg_security_parameters_seq_offset - 1 - 1);
01414     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset));
01415     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01416 
01417     /* complete missing length in scoped PDU sequence */
01418     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3);
01419     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset));
01420     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01421   }
01422 #endif
01423 
01424   /* complete missing length in 'PDU' sequence */
01425   SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3,
01426       frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
01427   OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) );
01428   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
01429 
01430   /* process and encode final error status */
01431   if (request->error_status != 0) {
01432     u16_t len;
01433     snmp_asn1_enc_s32t_cnt(request->error_status, &len);
01434     if (len != 1) {
01435       /* error, we only reserved one byte for it */
01436       return ERR_ARG;
01437     }
01438     OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) );
01439     OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) );
01440 
01441     /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */
01442     switch (request->error_status) {
01443       case SNMP_ERR_TOOBIG:
01444         snmp_stats.outtoobigs++;
01445         break;
01446       case SNMP_ERR_NOSUCHNAME:
01447         snmp_stats.outnosuchnames++;
01448         break;
01449       case SNMP_ERR_BADVALUE:
01450         snmp_stats.outbadvalues++;
01451         break;
01452       case SNMP_ERR_GENERROR:
01453       default:
01454         snmp_stats.outgenerrs++;
01455         break;
01456     }
01457 
01458     if (request->error_status == SNMP_ERR_TOOBIG) {
01459       request->error_index = 0; /* defined by RFC 1157 */
01460     } else if (request->error_index == 0) {
01461       /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */
01462       request->error_index = request->inbound_varbind_enumerator.varbind_count;
01463     }
01464   } else {
01465     if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
01466       snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count;
01467     } else {
01468       snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count;
01469     }
01470   }
01471 
01472   /* encode final error index*/
01473   if (request->error_index != 0) {
01474     u16_t len;
01475     snmp_asn1_enc_s32t_cnt(request->error_index, &len);
01476     if (len != 1) {
01477       /* error, we only reserved one byte for it */
01478       return ERR_VAL;
01479     }
01480     OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) );
01481     OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) );
01482   }
01483 
01484   /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */
01485   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset);
01486   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()) */
01487   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
01488 
01489   /* Authenticate response */
01490 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
01491   /* Encrypt response */
01492   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
01493     u8_t key[20];
01494     u8_t algo;
01495 
01496     /* complete missing length in PDU sequence */
01497     OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
01498     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset));
01499     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding
01500         - request->outbound_scoped_pdu_string_offset - 1 - 3);
01501     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
01502 
01503     OF_BUILD_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, &algo, key));
01504 
01505     OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key,
01506         request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
01507         request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT));
01508   }
01509 
01510   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) {
01511     u8_t key[20];
01512     u8_t algo;
01513     u8_t hmac[20];
01514 
01515     OF_BUILD_EXEC(snmpv3_get_user ((char*)request->msg_user_name, &algo, key, NULL, NULL));
01516     OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream),
01517         request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
01518     OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
01519 
01520     memcpy(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01521     OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream,
01522                   request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
01523     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream,
01524                   request->outbound_msg_authentication_parameters_offset));
01525 
01526     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
01527     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv));
01528     OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream,
01529                   request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
01530   }
01531 #endif
01532 
01533   pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding);
01534 
01535   snmp_stats.outgetresponses++;
01536   snmp_stats.outpkts++;
01537 
01538   return ERR_OK;
01539 }
01540 
01541 static void 
01542 snmp_execute_write_callbacks(struct snmp_request *request)
01543 {
01544   struct snmp_varbind_enumerator inbound_varbind_enumerator;
01545   struct snmp_varbind vb;
01546 
01547   snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
01548   vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
01549 
01550   while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == ERR_OK) {
01551     snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
01552   }
01553 }
01554 
01555 
01556 /* ----------------------------------------------------------------------- */
01557 /* VarBind enumerator methods */
01558 /* ----------------------------------------------------------------------- */
01559 
01560 void
01561 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length)
01562 {
01563   snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length);
01564   enumerator->varbind_count = 0;
01565 }
01566 
01567 #define VB_PARSE_EXEC(code)   PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
01568 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
01569 
01570 snmp_vb_enumerator_err_t
01571 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind)
01572 {
01573   struct snmp_asn1_tlv tlv;
01574   u16_t  varbind_len;
01575   err_t  err;
01576   
01577   if (enumerator->pbuf_stream.length == 0)
01578   {
01579     return SNMP_VB_ENUMERATOR_ERR_EOVB;
01580   }
01581   enumerator->varbind_count++;
01582 
01583   /* decode varbind itself (parent container of a varbind) */
01584   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
01585   VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
01586   varbind_len = tlv.value_len;
01587 
01588   /* decode varbind name (object id) */
01589   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
01590   VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
01591    
01592   VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
01593   varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);
01594 
01595   /* decode varbind value (object id) */
01596   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
01597   VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
01598   varbind->type = tlv.type;
01599 
01600   /* shall the value be decoded ? */
01601   if (varbind->value != NULL) {
01602     switch (varbind->type) {
01603       case SNMP_ASN1_TYPE_INTEGER:
01604         VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value));
01605         varbind->value_len = sizeof(s32_t*);
01606         break;
01607       case SNMP_ASN1_TYPE_COUNTER:
01608       case SNMP_ASN1_TYPE_GAUGE:
01609       case SNMP_ASN1_TYPE_TIMETICKS:
01610         VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
01611         varbind->value_len = sizeof(u32_t*);
01612         break;
01613       case SNMP_ASN1_TYPE_OCTET_STRING:
01614       case SNMP_ASN1_TYPE_OPAQUE:
01615         err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
01616         if (err == ERR_MEM) {
01617           return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
01618         }
01619         VB_PARSE_ASSERT(err == ERR_OK);
01620         break;
01621       case SNMP_ASN1_TYPE_NULL:
01622         varbind->value_len = 0;
01623         break;
01624       case SNMP_ASN1_TYPE_OBJECT_ID:
01625         /* misuse tlv.length_len as OID_length transporter */
01626         err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
01627         if (err == ERR_MEM) {
01628           return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
01629         }
01630         VB_PARSE_ASSERT(err == ERR_OK);
01631         varbind->value_len = tlv.length_len * sizeof(u32_t);
01632         break;
01633       case SNMP_ASN1_TYPE_IPADDR:
01634         if (tlv.value_len == 4) {
01635           /* must be exactly 4 octets! */
01636           VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
01637         } else {
01638           VB_PARSE_ASSERT(0);
01639         }
01640         break;
01641       case SNMP_ASN1_TYPE_COUNTER64:
01642         VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
01643         varbind->value_len = 2 * sizeof(u32_t*);
01644         break;
01645       default:
01646         VB_PARSE_ASSERT(0);
01647         break;
01648     }
01649   } else {
01650     snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
01651     varbind->value_len = tlv.value_len;
01652   }
01653 
01654   return SNMP_VB_ENUMERATOR_ERR_OK;
01655 }
01656 
01657 #endif /* LWIP_SNMP */