diff --git a/src/core/raw.c b/src/core/raw.c index 440e2b82..a37a6ea2 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -57,6 +57,47 @@ /** The list of RAW PCBs */ static struct raw_pcb *raw_pcbs; +static u8_t +raw_input_match(struct raw_pcb *pcb, u8_t broadcast) +{ + 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())) { +#if LWIP_IPV4 + /* Special case: IPv4 broadcast: receive all broadcasts + * 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))) { + return 1; + } + } + } else +#endif /* LWIP_IPV4 */ + /* Handle IPv4 and IPv6: catch all or exact match */ + if(ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + return 1; + } + } + + return 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. @@ -80,6 +121,7 @@ raw_input(struct pbuf *p, struct netif *inp) struct raw_pcb *pcb, *prev; s16_t proto; u8_t eaten = 0; + u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); LWIP_UNUSED_ARG(inp); @@ -106,44 +148,34 @@ raw_input(struct pbuf *p, struct netif *inp) /* 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_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr()) && - (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) { + if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) { + /* receive callback function available? */ + if (pcb->recv != NULL) { #ifndef LWIP_NOASSERT - void* old_payload = p->payload; + 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); + /* 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 */ + /* no receive callback function was set for this raw PCB */ } + /* drop the packet */ prev = pcb; pcb = pcb->next; } @@ -416,31 +448,30 @@ raw_new(u8_t proto) return pcb; } -#if LWIP_IPV6 /** * Create a RAW PCB for IPv6. * * @return The RAW PCB which was created. NULL if the PCB data structure * could not be allocated. * + * @param type IP address type, see IPADDR_TYPE_XX definitions. * @param proto the protocol number (next header) of the IPv6 packet payload * (e.g. IP6_NEXTH_ICMP6) * * @see raw_remove() */ struct raw_pcb * -raw_new_ip6(u8_t proto) +raw_new_ip_type(u8_t type, u8_t proto) { struct raw_pcb *pcb; pcb = raw_new(proto); -#if LWIP_IPV4 +#if LWIP_IPV4 && LWIP_IPV6 if(pcb != NULL) { - IP_SET_TYPE_VAL(pcb->local_ip, IPADDR_TYPE_V6); - IP_SET_TYPE_VAL(pcb->remote_ip, IPADDR_TYPE_V6); + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); } -#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV4 && LWIP_IPV6 */ return pcb; } -#endif /* LWIP_IPV6 */ #endif /* LWIP_RAW */ diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index f48127ee..474fdc15 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -83,6 +83,7 @@ struct raw_pcb { /* The following functions is the application layer interface to the RAW code. */ struct raw_pcb * raw_new (u8_t proto); +struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); void raw_remove (struct raw_pcb *pcb); err_t raw_bind (struct raw_pcb *pcb, const ip_addr_t *ipaddr); err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); @@ -92,14 +93,13 @@ err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); -#if LWIP_IPV6 -struct raw_pcb * raw_new_ip6 (u8_t proto); -#endif /* LWIP_IPV6 */ - /* The following functions are the lower layer interface to RAW. */ u8_t raw_input (struct pbuf *p, struct netif *inp); #define raw_init() /* Compatibility define, no init needed. */ +/* for compatibility with older implementation */ +#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) + #ifdef __cplusplus } #endif