/** * 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; }
/** * 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); }