Implement dual-stack in RAW API in the same way as in UDP and TCP

This commit is contained in:
Dirk Ziegelmeier 2016-03-03 22:47:27 +01:00
parent 2d80af1dcb
commit 7396d8818b
2 changed files with 74 additions and 43 deletions

View File

@ -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 */

View File

@ -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