⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msg_in.c

📁 STM32F107_ETH_LwIP_V1.0.0.rar
💻 C
📖 第 1 页 / 共 3 页
字号:
/**
 * @file
 * SNMP input message processing (RFC1157).
 */

/*
 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * Author: Christiaan Simons <christiaan.simons@axon.tv>
 */

#include "lwip/opt.h"

#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

#include "lwip/ip_addr.h"
#include "lwip/mem.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_msg.h"
#include "lwip/snmp_structs.h"

#include <string.h>

/* public (non-static) constants */
/** SNMP v1 == 0 */
const s32_t snmp_version = 0;
/** default SNMP community string */
const char snmp_publiccommunity[7] = "public";

/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
/* UDP Protocol Control Block */
struct udp_pcb *snmp1_pcb;

static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);


/**
 * Starts SNMP Agent.
 * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
 */
void
snmp_init(void)
{
  struct snmp_msg_pstat *msg_ps;
  u8_t i;

  snmp1_pcb = udp_new();
  if (snmp1_pcb != NULL)
  {
    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
  }
  msg_ps = &msg_input_list[0];
  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
  {
    msg_ps->state = SNMP_MSG_EMPTY;
    msg_ps->error_index = 0;
    msg_ps->error_status = SNMP_ES_NOERROR;
    msg_ps++;
  }
  trap_msg.pcb = snmp1_pcb;
  /* The coldstart trap will only be output
     if our outgoing interface is up & configured  */
  snmp_coldstart_trap();
}

static void
snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
{
  snmp_varbind_list_free(&msg_ps->outvb);
  msg_ps->outvb = msg_ps->invb;
  msg_ps->invb.head = NULL;
  msg_ps->invb.tail = NULL;
  msg_ps->invb.count = 0;
  msg_ps->error_status = error;
  msg_ps->error_index = 1 + msg_ps->vb_idx;
  snmp_send_response(msg_ps);
  snmp_varbind_list_free(&msg_ps->outvb);
  msg_ps->state = SNMP_MSG_EMPTY;
}

static void
snmp_ok_response(struct snmp_msg_pstat *msg_ps)
{
  err_t err_ret;

  err_ret = snmp_send_response(msg_ps);
  if (err_ret == ERR_MEM)
  {
    /* serious memory problem, can't return tooBig */
  }
  else
  {
    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
  }
  /* free varbinds (if available) */
  snmp_varbind_list_free(&msg_ps->invb);
  snmp_varbind_list_free(&msg_ps->outvb);
  msg_ps->state = SNMP_MSG_EMPTY;
}

/**
 * Service an internal or external event for SNMP GET.
 *
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 * @param msg_ps points to the assosicated message process state
 */
static void
snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
  {
    struct mib_external_node *en;
    struct snmp_name_ptr np;

    /* get_object_def() answer*/
    en = msg_ps->ext_mib_node;
    np = msg_ps->ext_name_ptr;

    /* translate answer into a known lifeform */
    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
    {
      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
      en->get_value_q(request_id, &msg_ps->ext_object_def);
    }
    else
    {
      en->get_object_def_pc(request_id, np.ident_len, np.ident);
      /* search failed, object id points to unknown object (nosuchname) */
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
    }
  }
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
  {
    struct mib_external_node *en;
    struct snmp_varbind *vb;

    /* get_value() answer */
    en = msg_ps->ext_mib_node;

    /* allocate output varbind */
    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
    LWIP_ASSERT("vb != NULL",vb != NULL);
    if (vb != NULL)
    {
      vb->next = NULL;
      vb->prev = NULL;

      /* move name from invb to outvb */
      vb->ident = msg_ps->vb_ptr->ident;
      vb->ident_len = msg_ps->vb_ptr->ident_len;
      /* ensure this memory is refereced once only */
      msg_ps->vb_ptr->ident = NULL;
      msg_ps->vb_ptr->ident_len = 0;

      vb->value_type = msg_ps->ext_object_def.asn_type;
      vb->value_len =  msg_ps->ext_object_def.v_len;
      if (vb->value_len > 0)
      {
        vb->value = mem_malloc(vb->value_len);
        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
        if (vb->value != NULL)
        {
          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
          snmp_varbind_tail_add(&msg_ps->outvb, vb);
          /* search again (if vb_idx < msg_ps->invb.count) */
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
          msg_ps->vb_idx += 1;
        }
        else
        {
          en->get_value_pc(request_id, &msg_ps->ext_object_def);
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
          msg_ps->vb_ptr->ident = vb->ident;
          msg_ps->vb_ptr->ident_len = vb->ident_len;
          mem_free(vb);
          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
        }
      }
      else
      {
        /* vb->value_len == 0, empty value (e.g. empty string) */
        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
        vb->value = NULL;
        snmp_varbind_tail_add(&msg_ps->outvb, vb);
        /* search again (if vb_idx < msg_ps->invb.count) */
        msg_ps->state = SNMP_MSG_SEARCH_OBJ;
        msg_ps->vb_idx += 1;
      }
    }
    else
    {
      en->get_value_pc(request_id, &msg_ps->ext_object_def);
      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
    }
  }

  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
         (msg_ps->vb_idx < msg_ps->invb.count))
  {
    struct mib_node *mn;
    struct snmp_name_ptr np;

    if (msg_ps->vb_idx == 0)
    {
      msg_ps->vb_ptr = msg_ps->invb.head;
    }
    else
    {
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
    }
    /** test object identifier for .iso.org.dod.internet prefix */
    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
    {
      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
                             msg_ps->vb_ptr->ident + 4, &np);
      if (mn != NULL)
      {
        if (mn->node_type == MIB_NODE_EX)
        {
          /* external object */
          struct mib_external_node *en = (struct mib_external_node*)mn;

          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
          /* save en && args in msg_ps!! */
          msg_ps->ext_mib_node = en;
          msg_ps->ext_name_ptr = np;

          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
        }
        else
        {
          /* internal object */
          struct obj_def object_def;

          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
          mn->get_object_def(np.ident_len, np.ident, &object_def);
          if (object_def.instance != MIB_OBJECT_NONE)
          {
            mn = mn;
          }
          else
          {
            /* search failed, object id points to unknown object (nosuchname) */
            mn =  NULL;
          }
          if (mn != NULL)
          {
            struct snmp_varbind *vb;

            msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
            /* allocate output varbind */
            vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
            LWIP_ASSERT("vb != NULL",vb != NULL);
            if (vb != NULL)
            {
              vb->next = NULL;
              vb->prev = NULL;

              /* move name from invb to outvb */
              vb->ident = msg_ps->vb_ptr->ident;
              vb->ident_len = msg_ps->vb_ptr->ident_len;
              /* ensure this memory is refereced once only */
              msg_ps->vb_ptr->ident = NULL;
              msg_ps->vb_ptr->ident_len = 0;

              vb->value_type = object_def.asn_type;
              vb->value_len = object_def.v_len;
              if (vb->value_len > 0)
              {
                vb->value = mem_malloc(vb->value_len);
                LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
                if (vb->value != NULL)
                {
                  mn->get_value(&object_def, vb->value_len, vb->value);
                  snmp_varbind_tail_add(&msg_ps->outvb, vb);
                  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
                  msg_ps->vb_idx += 1;
                }
                else
                {
                  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
                  msg_ps->vb_ptr->ident = vb->ident;
                  msg_ps->vb_ptr->ident_len = vb->ident_len;
                  mem_free(vb);
                  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
                }
              }
              else
              {
                /* vb->value_len == 0, empty value (e.g. empty string) */
                vb->value = NULL;
                snmp_varbind_tail_add(&msg_ps->outvb, vb);
                msg_ps->state = SNMP_MSG_SEARCH_OBJ;
                msg_ps->vb_idx += 1;
              }
            }
            else
            {
              LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
              snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
            }
          }
        }
      }
    }
    else
    {
      mn = NULL;
    }
    if (mn == NULL)
    {
      /* mn == NULL, noSuchName */
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
    }
  }
  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
      (msg_ps->vb_idx == msg_ps->invb.count))
  {
    snmp_ok_response(msg_ps);
  }
}

/**
 * Service an internal or external event for SNMP GETNEXT.
 *
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 * @param msg_ps points to the assosicated message process state
 */
static void
snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
  {
    struct mib_external_node *en;

    /* get_object_def() answer*/
    en = msg_ps->ext_mib_node;

    /* translate answer into a known lifeform */
    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
    {
      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
      en->get_value_q(request_id, &msg_ps->ext_object_def);
    }
    else
    {
      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
      /* search failed, object id points to unknown object (nosuchname) */
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
    }
  }
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
  {
    struct mib_external_node *en;
    struct snmp_varbind *vb;

    /* get_value() answer */
    en = msg_ps->ext_mib_node;

    vb = snmp_varbind_alloc(&msg_ps->ext_oid,
                            msg_ps->ext_object_def.asn_type,
                            msg_ps->ext_object_def.v_len);
    if (vb != NULL)
    {
      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
      snmp_varbind_tail_add(&msg_ps->outvb, vb);
      msg_ps->state = SNMP_MSG_SEARCH_OBJ;
      msg_ps->vb_idx += 1;
    }
    else
    {
      en->get_value_pc(request_id, &msg_ps->ext_object_def);
      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
    }
  }

  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
         (msg_ps->vb_idx < msg_ps->invb.count))
  {
    struct mib_node *mn;
    struct snmp_obj_id oid;

    if (msg_ps->vb_idx == 0)
    {
      msg_ps->vb_ptr = msg_ps->invb.head;
    }
    else
    {
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
    }
    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
    {
      if (msg_ps->vb_ptr->ident_len > 3)
      {
        /* can offset ident_len and ident */
        mn = snmp_expand_tree((struct mib_node*)&internet,
                              msg_ps->vb_ptr->ident_len - 4,
                              msg_ps->vb_ptr->ident + 4, &oid);
      }
      else
      {
        /* can't offset ident_len -4, ident + 4 */
        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
      }
    }
    else
    {
      mn = NULL;
    }
    if (mn != NULL)
    {
      if (mn->node_type == MIB_NODE_EX)
      {
        /* external object */
        struct mib_external_node *en = (struct mib_external_node*)mn;

        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
        /* save en && args in msg_ps!! */
        msg_ps->ext_mib_node = en;
        msg_ps->ext_oid = oid;

        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
      }
      else
      {
        /* internal object */
        struct obj_def object_def;
        struct snmp_varbind *vb;

        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);

        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
        if (vb != NULL)
        {
          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
          mn->get_value(&object_def, object_def.v_len, vb->value);
          snmp_varbind_tail_add(&msg_ps->outvb, vb);
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
          msg_ps->vb_idx += 1;
        }
        else
        {
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
        }
      }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -