Rtos API example

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