Esempio n. 1
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 ICACHE_FLASH_ATTR
raw_input(struct pbuf *p, struct netif *inp)
{
  struct raw_pcb *pcb, *prev;
  struct ip_hdr *iphdr;
  s16_t proto;
  u8_t eaten = 0;
#if LWIP_IPV6
  struct ip6_hdr *ip6hdr;
#endif /* LWIP_IPV6 */


  LWIP_UNUSED_ARG(inp);

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

  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_PCB_IPVER_INPUT_MATCH(pcb) &&
        (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) ||
         ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) {
#if IP_SOF_BROADCAST_RECV
      /* broadcast filter? */
      if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
#if LWIP_IPV6
          && !PCB_ISIPV6(pcb)
#endif /* LWIP_IPV6 */
          )
#endif /* IP_SOF_BROADCAST_RECV */
      {
        /* receive callback function available? */
        if (pcb->recv.ip4 != NULL) {
#ifndef LWIP_NOASSERT
          void* old_payload = p->payload;
#endif
          /* the receive callback function did not eat the packet? */
          eaten = pcb->recv.ip4(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;
}
Esempio n. 2
0
/**
 * Lwip thread callback invoked via fwudp::msg_send
 */
void
fwudp_pcb_send(void *arg)
{
    struct fwudp *fwudp = (struct fwudp *)arg;
    struct fwudp_dgram dgram;
    struct udp_pcb *pcb;
    struct udp_pcb **pprev;
    int isv6;
    size_t idx;

    idx = fwudp->inbuf.unsent;

    if (idx == fwudp->inbuf.vacant) {
        /* empty buffer - shouldn't happen! */
        DPRINTF(("%s: ring buffer empty!\n", __func__));
        return;
    }

    dgram = fwudp->inbuf.buf[idx]; /* struct copy */
#if 1 /* valgrind hint */
    fwudp->inbuf.buf[idx].p = NULL;
#endif
    if (++idx == fwudp->inbuf.bufsize) {
        idx = 0;
    }
    fwudp->inbuf.unsent = idx;

    /* XXX: this is *STUPID* */
    isv6 = (fwudp->fwspec.sdom == PF_INET6);
    pprev = &udp_proxy_pcbs;
    for (pcb = udp_proxy_pcbs; pcb != NULL; pcb = pcb->next) {
        if (PCB_ISIPV6(pcb) == isv6
            && pcb->remote_port == fwudp->dst_port
            && ipX_addr_cmp(isv6, &fwudp->dst_addr, &pcb->remote_ip)
            && pcb->local_port == dgram.src_port
            && ipX_addr_cmp(isv6, &dgram.src_addr, &pcb->local_ip))
        {
            break;
        }
        else {
            pprev = &pcb->next;
        }
    }

    if (pcb != NULL) {
        *pprev = pcb->next;
        pcb->next = udp_proxy_pcbs;
        udp_proxy_pcbs = pcb;

        /*
         * XXX: check that its ours and not accidentally created by
         * outbound traffic.
         *
         * ???: Otherwise?  Expire it and set pcb = NULL; to create a
         * new one below?
         */
    }

    if (pcb == NULL) {
        pcb = udp_new();
        if (pcb == NULL) {
            goto out;
        }

        ip_set_v6(pcb, isv6);

        /* equivalent of udp_bind */
        ipX_addr_set(isv6, &pcb->local_ip, &dgram.src_addr);
        pcb->local_port = dgram.src_port;

        /* equivalent to udp_connect */
        ipX_addr_set(isv6, &pcb->remote_ip, &fwudp->dst_addr);
        pcb->remote_port = fwudp->dst_port;
        pcb->flags |= UDP_FLAGS_CONNECTED;

        udp_recv(pcb, fwudp_pcb_recv, fwudp);

        pcb->next = udp_proxy_pcbs;
        udp_proxy_pcbs = pcb;
        udp_proxy_timer_needed();
    }

    udp_send(pcb, dgram.p);

  out:
    pbuf_free(dgram.p);
}