Exemple #1
0
/*-----------------------------------------------------------------------------------*/
static void
delif_output_timeout(void *arg)
{
  struct netif *netif;
  struct delif *delif;
  struct delif_pbuf *dp;
  unsigned int timeout, now;

  timeout = DELIF_TIMEOUT;

  netif = (struct netif*)arg;
  delif = (struct delif*)netif->state;

  /* Check if there is anything on the output list. */
  dp = output_list;
  while (dp != NULL) {
    now = sys_now();
    if (dp->time <= now) {
      LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: now %u dp->time %u\n",
        now, dp->time));

#if LWIP_IPV4
      if(!IP_IS_V6_VAL(dp->ipaddr)) {
        delif->netif->output(delif->netif, dp->p, ip_2_ip4(&dp->ipaddr));
      }
#endif /* LWIP_IPV4 */

#if LWIP_IPV6
      if(IP_IS_V6_VAL(dp->ipaddr)) {
        delif->netif->output_ip6(delif->netif, dp->p, ip_2_ip6(&dp->ipaddr));
      }
#endif /* LWIP_IPV6 */

      if (dp->next != NULL) {
        if (dp->next->time > now) {
          timeout = dp->next->time - now;
        } else {
          timeout = 0;
        }
        LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout));

      }
      pbuf_free(dp->p);

      output_list = dp->next;
      free(dp);
      dp = output_list;
    } else {
      dp = dp->next;	
    }
  }

  sys_timeout(timeout, delif_output_timeout, arg);
}
Exemple #2
0
/**
 * Sums trap header field lengths from tail to head and
 * returns trap_header_lengths for second encoding pass.
 *
 * @param vb_len varbind-list length
 * @param thl points to returned header lengths
 * @return the required length for encoding the trap header
 */
static u16_t
snmp_trap_header_sum(struct snmp_msg_trap *trap)
{
  u16_t tot_len;
  u16_t len;
  u8_t lenlen;

  tot_len = 0;

  snmp_asn1_enc_u32t_cnt(trap->ts, &len);
  snmp_asn1_enc_length_cnt(len, &lenlen);
  tot_len += 1 + len + lenlen;

  snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len);
  snmp_asn1_enc_length_cnt(len, &lenlen);
  tot_len += 1 + len + lenlen;

  snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len);
  snmp_asn1_enc_length_cnt(len, &lenlen);
  tot_len += 1 + len + lenlen;

  if(IP_IS_V6_VAL(trap->sip)) {
#if LWIP_IPV6
    len = sizeof(ip_2_ip6(&trap->sip)->addr);
#endif
  } else {
#if LWIP_IPV4
    len = sizeof(ip_2_ip4(&trap->sip)->addr);
#endif
  }
  snmp_asn1_enc_length_cnt(len, &lenlen);
  tot_len += 1 + len + lenlen;

  snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len);
  snmp_asn1_enc_length_cnt(len, &lenlen);
  tot_len += 1 + len + lenlen;

  trap->pdulen = tot_len;
  snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen);
  tot_len += 1 + lenlen;

  trap->comlen = (u16_t)strlen(snmp_community_trap);
  snmp_asn1_enc_length_cnt(trap->comlen, &lenlen);
  tot_len += 1 + lenlen + trap->comlen;

  snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len);
  snmp_asn1_enc_length_cnt(len, &lenlen);
  tot_len += 1 + len + lenlen;

  trap->seqlen = tot_len;
  snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen);
  tot_len += 1 + lenlen;

  return tot_len;
}
static snmp_err_t
tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  u8_t i;
  struct tcp_pcb *pcb;
  struct snmp_next_oid_state state;
  u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
    pcb = *tcp_pcb_lists[i];
    while (pcb != NULL) {
      u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];

      if (IP_IS_V4_VAL(pcb->local_ip)) {
        snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
        test_oid[4] = pcb->local_port;

        /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
        if (pcb->state == LISTEN) {
          snmp_ip4_to_oid(IP4_ADDR_ANY, &test_oid[5]);
          test_oid[9] = 0;
        } else {
          if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */
            continue;
          }
          snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]);
          test_oid[9] = pcb->remote_port;
        }

        /* check generated OID: is it a candidate for the next one? */
        snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb);
      }

      pcb = pcb->next;
    }
  }

  /* did we find a next one? */
  if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len);
  }

  /* not found */
  return SNMP_ERR_NOSUCHINSTANCE;
}
Exemple #4
0
/** Common code to see if the current input packet matches the pcb
 * (current input packet is accessed via ip(4/6)_current_* macros)
 *
 * @param pcb pcb to check
 * @param inp network interface on which the datagram was received (only used for IPv4)
 * @param broadcast 1 if his is an IPv4 broadcast (global or subnet-only), 0 otherwise (only used for IPv4)
 * @return 1 on match, 0 otherwise
 */
static u8_t ESP_IRAM_ATTR
udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
{
  LWIP_UNUSED_ARG(inp);       /* in IPv6 only case */
  LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */

  /* Dual-stack: PCBs listening to any IP type also listen to any IP address */
  if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
#if LWIP_IPV4 && IP_SOF_BROADCAST_RECV
    if((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) {
      return 0;
    }
#endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */
    return 1;
  }

  /* Only need to check PCB if incoming IP version matches PCB IP version */
  if(IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) {
    LWIP_ASSERT("UDP PCB: inconsistent local/remote IP versions", IP_IS_V6_VAL(pcb->local_ip) == IP_IS_V6_VAL(pcb->remote_ip));

#if LWIP_IPV4
    /* Special case: IPv4 broadcast: all or broadcasts in my subnet
     * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */
    if(broadcast != 0) {
#if IP_SOF_BROADCAST_RECV
      if(ip_get_option(pcb, SOF_BROADCAST))
#endif /* IP_SOF_BROADCAST_RECV */
      {
        if(ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) ||
          ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) ||
           ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) {
          return 1;
        }
      }
    } else
#endif /* LWIP_IPV4 */
    /* Handle IPv4 and IPv6: all, multicast or exact match */
    if(ip_addr_isany(&pcb->local_ip) ||
#if LWIP_IPV6_MLD
       (ip_current_is_v6() && ip6_addr_ismulticast(ip6_current_dest_addr())) ||
#endif /* LWIP_IPV6_MLD */
#if LWIP_IGMP
       (!ip_current_is_v6() && ip4_addr_ismulticast(ip4_current_dest_addr())) ||
#endif /* LWIP_IGMP */
       ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
      return 1;
    }
  }
  
  return 0;
}
Exemple #5
0
/**
 * Encodes trap header from head to tail.
 */
static void
snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream)
{
  struct snmp_asn1_tlv tlv;

  /* 'Message' sequence */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);

  /* version */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
  snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);
  snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version);

  /* community */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);
  snmp_asn1_enc_raw(pbuf_stream,  (const u8_t *)snmp_community_trap, trap->comlen);

  /* 'PDU' sequence */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);

  /* object ID */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0);
  snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);
  snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len);

  /* IP addr */
  if(IP_IS_V6_VAL(trap->sip)) {
#if LWIP_IPV6
    SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr));
    snmp_ans1_enc_tlv(pbuf_stream, &tlv);
    snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr));
#endif
  } else {
#if LWIP_IPV4
    SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr));
    snmp_ans1_enc_tlv(pbuf_stream, &tlv);
    snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr));
#endif
  }

  /* trap length */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
  snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);
  snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap);

  /* specific trap */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
  snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);
  snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap);

  /* timestamp */
  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0);
  snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len);
  snmp_ans1_enc_tlv(pbuf_stream, &tlv);
  snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts);
}
Exemple #6
0
/**
 * Translates the name of a service location (for example, a host name) and/or
 * a service name and returns a set of socket addresses and associated
 * information to be used in creating a socket with which to address the
 * specified service.
 * Memory for the result is allocated internally and must be freed by calling
 * lwip_freeaddrinfo()!
 *
 * Due to a limitation in dns_gethostbyname, only the first address of a
 * host is returned.
 * Also, service names are not supported (only port numbers)!
 *
 * @param nodename descriptive name or address string of the host
 *                 (may be NULL -> local address)
 * @param servname port number as string of NULL
 * @param hints structure containing input values that set socktype and protocol
 * @param res pointer to a pointer where to store the result (set to NULL on failure)
 * @return 0 on success, non-zero on failure
 *
 * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
 */
int
lwip_getaddrinfo(const char *nodename, const char *servname,
       const struct addrinfo *hints, struct addrinfo **res)
{
  err_t err;
  ip_addr_t addr;
  struct addrinfo *ai;
  struct sockaddr_storage *sa = NULL;
  int port_nr = 0;
  size_t total_size;
  size_t namelen = 0;
  int ai_family;

  if (res == NULL) {
    return EAI_FAIL;
  }
  *res = NULL;
  if ((nodename == NULL) && (servname == NULL)) {
    return EAI_NONAME;
  }

  if (hints != NULL) {
    ai_family = hints->ai_family;
    if ((ai_family != AF_UNSPEC)
#if LWIP_IPV4
      && (ai_family != AF_INET)
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
      && (ai_family != AF_INET6)
#endif /* LWIP_IPV6 */
      ) {
      return EAI_FAMILY;
    }
  } else {
    ai_family = AF_UNSPEC;
  }

  if (servname != NULL) {
    /* service name specified: convert to port number
     * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
    port_nr = atoi(servname);
    if ((port_nr <= 0) || (port_nr > 0xffff)) {
      return EAI_SERVICE;
    }
  }

  if (nodename != NULL) {
    /* service location specified, try to resolve */
    if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
      /* no DNS lookup, just parse for an address string */
      if (!ipaddr_aton(nodename, &addr)) {
        return EAI_NONAME;
      }
#if LWIP_IPV4 && LWIP_IPV6
      if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
          (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
        return EAI_NONAME;
      }
#endif /* LWIP_IPV4 && LWIP_IPV6 */
    } else {
#if LWIP_IPV4 && LWIP_IPV6
      /* AF_UNSPEC: prefer IPv4 */
      u8_t type = NETCONN_DNS_IPV4_IPV6;
      if (ai_family == AF_INET) {
        type = NETCONN_DNS_IPV4;
      } else if (ai_family == AF_INET6) {
        type = NETCONN_DNS_IPV6;
      }
#endif /* LWIP_IPV4 && LWIP_IPV6 */
      err = netconn_gethostbyname_addrtype(nodename, &addr, type);
      if (err != ERR_OK) {
        return EAI_FAIL;
      }
    }
  } else {
    /* service location specified, use loopback address */
    if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
      ip_addr_set_any(ai_family == AF_INET6, &addr);
    } else {
      ip_addr_set_loopback(ai_family == AF_INET6, &addr);
    }
  }

  total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
  if (nodename != NULL) {
    namelen = strlen(nodename);
    if (namelen > DNS_MAX_NAME_LENGTH) {
      /* invalid name length */
      return EAI_FAIL;
    }
    LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
    total_size += namelen + 1;
  }
  /* If this fails, please report to lwip-devel! :-) */
  LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
    total_size <= NETDB_ELEM_SIZE);
  ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
  if (ai == NULL) {
    return EAI_MEMORY;
  }
  memset(ai, 0, total_size);
  /* cast through void* to get rid of alignment warnings */
  sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo));
  if (IP_IS_V6_VAL(addr)) {
#if LWIP_IPV6
    struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa;
    /* set up sockaddr */
    inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
    sa6->sin6_family = AF_INET6;
    sa6->sin6_len = sizeof(struct sockaddr_in6);
    sa6->sin6_port = lwip_htons((u16_t)port_nr);
    ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */
  } else {
#if LWIP_IPV4
    struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
    /* set up sockaddr */
    inet4_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
    sa4->sin_family = AF_INET;
    sa4->sin_len = sizeof(struct sockaddr_in);
    sa4->sin_port = lwip_htons((u16_t)port_nr);
    ai->ai_family = AF_INET;
#endif /* LWIP_IPV4 */
  }

  /* set up addrinfo */
  if (hints != NULL) {
    /* copy socktype & protocol from hints if specified */
    ai->ai_socktype = hints->ai_socktype;
    ai->ai_protocol = hints->ai_protocol;
  }
  if (nodename != NULL) {
    /* copy nodename to canonname if specified */
    ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
    MEMCPY(ai->ai_canonname, nodename, namelen);
    ai->ai_canonname[namelen] = 0;
  }
  ai->ai_addrlen = sizeof(struct sockaddr_storage);
  ai->ai_addr = (struct sockaddr*)sa;

  *res = ai;

  return 0;
}
Exemple #7
0
/**
 * Sends an generic or enterprise specific trap message.
 *
 * @param generic_trap is the trap code
 * @param eoid points to enterprise object identifier
 * @param specific_trap used for enterprise traps when generic_trap == 6
 * @return ERR_OK when success, ERR_MEM if we're out of memory
 *
 * @note the caller is responsible for filling in outvb in the trap_msg
 * @note the use of the enterprise identifier field
 * is per RFC1215.
 * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
 * and .iso.org.dod.internet.private.enterprises.yourenterprise
 * (sysObjectID) for specific traps.
 */
err_t
snmp_send_trap(s8_t generic_trap, const struct snmp_obj_id *eoid, s32_t specific_trap)
{
  struct snmp_trap_dst *td;
  struct netif *dst_if;
  const ip_addr_t* dst_ip;
  struct pbuf *p;
  u16_t i,tot_len;
  err_t err = ERR_OK;

  for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) {
    if ((td->enable != 0) && !ip_addr_isany(&td->dip)) {
      /* network order trap destination */
      ip_addr_copy(trap_msg.dip, td->dip);
      /* lookup current source address for this dst */
      ip_route_get_local_ip(PCB_ISIPV6(trap_msg.pcb), &trap_msg.pcb->local_ip,
        &td->dip, dst_if, dst_ip);
      if ((dst_if != NULL) && (dst_ip != NULL)) {
        trap_msg.sip_raw_len = (IP_IS_V6_VAL(*dst_ip) ? 16 : 4);
        memcpy(trap_msg.sip_raw, dst_ip, trap_msg.sip_raw_len);
        trap_msg.gen_trap = generic_trap;
        trap_msg.spc_trap = specific_trap;
        if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) {
          /* enterprise-Specific trap */
          trap_msg.enterprise = eoid;
        } else {
          /* generic (MIB-II) trap */
          mib2_get_snmpgrpid_ptr(&trap_msg.enterprise);
        }

        MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts);

        /* pass 0, calculate length fields */
        tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
        tot_len = snmp_trap_header_sum(&trap_msg, tot_len);

        /* allocate pbuf(s) */
        p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
        if (p != NULL) {
          u16_t ofs;

          /* pass 1, encode packet ino the pbuf(s) */
          ofs = snmp_trap_header_enc(&trap_msg, p);
          snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);

          mib2_inc_snmpouttraps();
          mib2_inc_snmpoutpkts();

          /** send to the TRAP destination */
          udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);

          pbuf_free(p);
        } else {
          err = ERR_MEM;
        }
      } else {
        /* routing error */
        err = ERR_RTE;
      }
    }
  }
  return err;
}
Exemple #8
0
/**
 * Determine if in incoming IP packet is covered by a RAW PCB
 * and if so, pass it to a user-provided receive callback function.
 *
 * Given an incoming IP datagram (as a chain of pbufs) this function
 * finds a corresponding RAW PCB and calls the corresponding receive
 * callback function.
 *
 * @param p pbuf to be demultiplexed to a RAW PCB.
 * @param inp network interface on which the datagram was received.
 * @return - 1 if the packet has been eaten by a RAW PCB receive
 *           callback function. The caller MAY NOT not reference the
 *           packet any longer, and MAY NOT call pbuf_free().
 * @return - 0 if packet is not eaten (pbuf is still referenced by the
 *           caller).
 *
 */
u8_t
raw_input(struct pbuf *p, struct netif *inp)
{
  struct raw_pcb *pcb, *prev;
  s16_t proto;
  u8_t eaten = 0;

  LWIP_UNUSED_ARG(inp);

#if LWIP_IPV6
#if LWIP_IPV4
  if (IP_HDR_GET_VERSION(p->payload) == 6)
#endif /* LWIP_IPV4 */
  {
    struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
    proto = IP6H_NEXTH(ip6hdr);
  }
#if LWIP_IPV4
  else
#endif /* LWIP_IPV4 */
#endif /* LWIP_IPV6 */
#if LWIP_IPV4
  {
    proto = IPH_PROTO((struct ip_hdr *)p->payload);
  }
#endif /* LWIP_IPV4 */

  prev = NULL;
  pcb = raw_pcbs;
  /* loop through all raw pcbs until the packet is eaten by one */
  /* this allows multiple pcbs to match against the packet by design */
  while ((eaten == 0) && (pcb != NULL)) {
    if ((pcb->protocol == proto) && (ip_current_is_v6() == IP_IS_V6_VAL(pcb->local_ip)) &&
        (ip_addr_isany(&pcb->local_ip) ||
         ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr()))) {
#if IP_SOF_BROADCAST_RECV
      /* broadcast filter? */
      if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()))
          || IP_IS_V6_VAL(pcb->local_ip)
          )
#endif /* IP_SOF_BROADCAST_RECV */
      {
        /* receive callback function available? */
        if (pcb->recv != NULL) {
#ifndef LWIP_NOASSERT
          void* old_payload = p->payload;
#endif
          /* the receive callback function did not eat the packet? */
          eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr());
          if (eaten != 0) {
            /* receive function ate the packet */
            p = NULL;
            eaten = 1;
            if (prev != NULL) {
            /* move the pcb to the front of raw_pcbs so that is
               found faster next time */
              prev->next = pcb->next;
              pcb->next = raw_pcbs;
              raw_pcbs = pcb;
            }
          } else {
            /* sanity-check that the receive callback did not alter the pbuf */
            LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet",
              p->payload == old_payload);
          }
        }
        /* no receive callback function was set for this raw PCB */
      }
      /* drop the packet */
    }
    prev = pcb;
    pcb = pcb->next;
  }
  return eaten;
}