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

📄 msg_in.c

📁 STM32F107_ETH_LwIP_V1.0.0.rar
💻 C
📖 第 1 页 / 共 3 页
字号:
    }
    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 SET.
 *
 * @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_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_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_SET_TEST;
      en->set_test_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_SET_TEST)
  {
    struct mib_external_node *en;

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

    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
    {
       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
           (en->set_test_a(request_id,&msg_ps->ext_object_def,
                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
      {
        msg_ps->state = SNMP_MSG_SEARCH_OBJ;
        msg_ps->vb_idx += 1;
      }
      else
      {
        en->set_test_pc(request_id,&msg_ps->ext_object_def);
        /* bad value */
        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
      }
    }
    else
    {
      en->set_test_pc(request_id,&msg_ps->ext_object_def);
      /* object not available for set */
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
    }
  }
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
  {
    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_SET_VALUE;
      en->set_value_q(request_id, &msg_ps->ext_object_def,
                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
    }
    else
    {
      en->get_object_def_pc(request_id, np.ident_len, np.ident);
      /* set_value failed, object has disappeared for some odd reason?? */
      snmp_error_response(msg_ps,SNMP_ES_GENERROR);
    }
  }
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
  {
    struct mib_external_node *en;

    /** set_value_a() */
    en = msg_ps->ext_mib_node;
    en->set_value_a(request_id, &msg_ps->ext_object_def,
      msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);

    /** @todo use set_value_pc() if toobig */
    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
    msg_ps->vb_idx += 1;
  }

  /* test all values before setting */
  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)
          {
            msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;

            if (object_def.access == MIB_OBJECT_READ_WRITE)
            {
              if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
                  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
              {
                msg_ps->state = SNMP_MSG_SEARCH_OBJ;
                msg_ps->vb_idx += 1;
              }
              else
              {
                /* bad value */
                snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
              }
            }
            else
            {
              /* object not available for set */
              snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
            }
          }
        }
      }
    }
    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))
  {
    msg_ps->vb_idx = 0;
    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
  }

  /* set all values "atomically" (be as "atomic" as possible) */
  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
         (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;
    }
    /* skip iso prefix test, was done previously while settesting() */
    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
                           msg_ps->vb_ptr->ident + 4, &np);
    /* check if object is still available
       (e.g. external hot-plug thingy present?) */
    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_S;
        /* 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_S;
        mn->get_object_def(np.ident_len, np.ident, &object_def);
        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
        msg_ps->vb_idx += 1;
      }
    }
  }
  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
      (msg_ps->vb_idx == msg_ps->invb.count))
  {
    /* simply echo the input if we can set it
       @todo do we need to return the actual value?
       e.g. if value is silently modified or behaves sticky? */
    msg_ps->outvb = msg_ps->invb;
    msg_ps->invb.head = NULL;
    msg_ps->invb.tail = NULL;
    msg_ps->invb.count = 0;
    snmp_ok_response(msg_ps);
  }
}


/**
 * Handle one internal or external event.
 * Called for one async event. (recv external/private answer)
 *
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 */
void
snmp_msg_event(u8_t request_id)
{
  struct snmp_msg_pstat *msg_ps;

  if (request_id < SNMP_CONCURRENT_REQUESTS)
  {
    msg_ps = &msg_input_list[request_id];
    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
    {
      snmp_msg_getnext_event(request_id, msg_ps);
    }
    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
    {
      snmp_msg_get_event(request_id, msg_ps);
    }
    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
    {
      snmp_msg_set_event(request_id, msg_ps);
    }
  }
}


/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
  struct udp_hdr *udphdr;

  /* suppress unused argument warning */
  LWIP_UNUSED_ARG(arg);
  /* peek in the UDP header (goto IP payload) */
  if(pbuf_header(p, UDP_HLEN)){
    LWIP_ASSERT("Can't move to UDP header", 0);
    pbuf_free(p);
    return;
  }
  udphdr = p->payload;

  /* check if datagram is really directed at us (including broadcast requests) */
  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
  {
    struct snmp_msg_pstat *msg_ps;
    u8_t req_idx;

    /* traverse input message process list, look for SNMP_MSG_EMPTY */
    msg_ps = &msg_input_list[0];
    req_idx = 0;
    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
    {
      req_idx++;
      msg_ps++;
    }
    if (req_idx != SNMP_CONCURRENT_REQUESTS)
    {
      err_t err_ret;
      u16_t payload_len;
      u16_t payload_ofs;
      u16_t varbind_ofs = 0;

      /* accepting request */
      snmp_inc_snmpinpkts();
      /* record used 'protocol control block' */
      msg_ps->pcb = pcb;
      /* source address (network order) */
      msg_ps->sip = *addr;
      /* source port (host order (lwIP oddity)) */
      msg_ps->sp = port;
      /* read UDP payload length from UDP header */
      payload_len = ntohs(udphdr->len) - UDP_HLEN;

      /* adjust to UDP payload */
      payload_ofs = UDP_HLEN;

      /* check total length, version, community, pdu type */
      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
          ((msg_ps->error_status == SNMP_ES_NOERROR) &&
           (msg_ps->error_index == 0)) )
      {
        /* Only accept requests and requests without error (be robust) */
        err_ret = err_ret;
      }
      else
      {
        /* Reject response and trap headers or error requests as input! */
        err_ret = ERR_ARG;
      }
      if (err_ret == ERR_OK)
      {
        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));

        /* Builds a list of variable bindings. Copy the varbinds from the pbuf
          chain to glue them when these are divided over two or more pbuf's. */
        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
        {
          /* we've decoded the incoming message, release input msg now */
          pbuf_free(p);

          msg_ps->error_status = SNMP_ES_NOERROR;
          msg_ps->error_index = 0;
          /* find object for each variable binding */
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
          /* first variable binding from list to inspect */
          msg_ps->vb_idx = 0;

          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));

          /* handle input event and as much objects as possible in one go */
          snmp_msg_event(req_idx);
        }
        else
        {
          /* varbind-list decode failed, or varbind list empty.
             drop request silently, do not return error!
             (errors are only returned for a specific varbind failure) */
          pbuf_free(p);
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
        }
      }
      else
      {
        /* header check failed
           drop request silently, do not return error! */
        pbuf_free(p);
        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
      }
    }
    else
    {
      /* exceeding number of concurrent requests */
      pbuf_free(p);
    }
  }
  else
  {
    /* datagram not for us */
    pbuf_free(p);
  }
}

/**
 * Checks and decodes incoming SNMP message header, logs header errors.
 *
 * @param p points to pbuf chain of SNMP message (UDP payload)
 * @param ofs points to first octet of SNMP message
 * @param pdu_len the length of the UDP payload
 * @param ofs_ret returns the ofset of the variable bindings
 * @param m_stat points to the current message request state return
 * @return
 * - ERR_OK SNMP header is sane and accepted
 * - ERR_ARG SNMP header is either malformed or rejected
 */
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)
{
  err_t derr;
  u16_t len, ofs_base;
  u8_t  len_octets;
  u8_t  type;
  s32_t version;

  ofs_base = ofs;
  snmp_asn1_dec_type(p, ofs, &type);
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
  if ((derr != ERR_OK) ||
      (pdu_len != (1 + len_octets + len)) ||
      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
  {
    snmp_inc_snmpinasnparseerrs();
    return ERR_ARG;
  }
  ofs += (1 + len_octets);
  snmp_asn1_dec_type(p, ofs, &type);
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
  {
    /* can't decode or no integer (version) */
    snmp_inc_snmpinasnparseerrs();
    return ERR_ARG;
  }
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
  if (derr != ERR_OK)
  {
    /* can't decode */
    snmp_inc_snmpinasnparseerrs();
    return ERR_ARG;
  }
  if (version != 0)
  {
    /* not version 1 */
    snmp_inc_snmpinbadversions();
    return ERR_ARG;
  }
  ofs += (1 + len_octets + len);
  snmp_asn1_dec_type(p, ofs, &type);
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
  {
    /* can't decode or no octet string (community) */
    snmp_inc_snmpinasnparseerrs();
    return ERR_ARG;

⌨️ 快捷键说明

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