From ac4b089b1837a0330bccae20bed43863f969b0a0 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 24 Feb 2016 19:57:20 +0100 Subject: [PATCH] udp.c: Further udp_input simplifications - Move local PCB matching code in a function that can be reused in SO_REUSE && SO_REUSE_RXTOALL case. - Some checks have been written in the dual-stack version and then repeated with the ipv6-only version. Example: IPv6 only: ip6_addr_ismulticast(ip6_current_dest_addr()) IPv4 AND IPv6: ip_addr_ismulticast(ip_current_dest_addr()) --- src/core/udp.c | 182 +++++++++++++++++++------------------------------ 1 file changed, 70 insertions(+), 112 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index fc42bea8..7a088053 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -138,6 +138,50 @@ again: #endif } +static u8_t +pcb_local_match(struct udp_pcb *pcb, struct netif *netif, u8_t broadcast) +{ + LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ + + /* TODO: Add special dualstack case here */ + + /* Only need to check PCB if incoming IP version matches PCB IP version */ + if(ip_current_is_v6() == IP_IS_V6_VAL(pcb->local_ip)) { + 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_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(netif))) { + 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; +} + /** * Process an incoming UDP datagram. * @@ -157,10 +201,7 @@ udp_input(struct pbuf *p, struct netif *inp) struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; u16_t src, dest; - u8_t local_match; -#if LWIP_IPV4 u8_t broadcast; -#endif /* LWIP_IPV4 */ u8_t for_us = 0; LWIP_UNUSED_ARG(inp); @@ -183,10 +224,8 @@ udp_input(struct pbuf *p, struct netif *inp) udphdr = (struct udp_hdr *)p->payload; -#if LWIP_IPV4 /* is broadcast packet ? */ broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); -#endif /* LWIP_IPV4 */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); @@ -225,14 +264,12 @@ udp_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_DHCP */ { prev = NULL; - local_match = 0; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { - local_match = 0; /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip); @@ -241,67 +278,29 @@ udp_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ - if (pcb->local_port == dest) { - - /* TODO: Add special dualstack case here */ - - /* Only need to check PCB if incoming IP version matches PCB IP version */ - if(ip_current_is_v6() == IP_IS_V6_VAL(pcb->local_ip)) { - 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_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { - local_match = 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())) { - local_match = 1; - } - } + if ((pcb->local_port == dest) && + (pcb_local_match(pcb, inp, broadcast) != 0)) { + if ((uncon_pcb == NULL) && + ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { + /* the first unconnected matching PCB */ + uncon_pcb = pcb; } - - if(local_match != 0) { - if ((uncon_pcb == NULL) && - ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { - /* the first unconnected matching PCB */ - uncon_pcb = pcb; - } - - /* compare PCB remote addr+port to UDP source addr+port */ - if ((pcb->remote_port == src) && - (ip_addr_isany_val(pcb->remote_ip) || - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { - /* the first fully matching PCB */ - if (prev != NULL) { - /* move the pcb to the front of udp_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = udp_pcbs; - udp_pcbs = pcb; - } else { - UDP_STATS_INC(udp.cachehit); - } - break; + + /* compare PCB remote addr+port to UDP source addr+port */ + if ((pcb->remote_port == src) && + (ip_addr_isany_val(pcb->remote_ip) || + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { + /* the first fully matching PCB */ + if (prev != NULL) { + /* move the pcb to the front of udp_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } else { + UDP_STATS_INC(udp.cachehit); } + break; } } @@ -374,18 +373,12 @@ udp_input(struct pbuf *p, struct netif *inp) pbuf_free(p); goto end; } + if (pcb != NULL) { MIB2_STATS_INC(mib2.udpindatagrams); #if SO_REUSE && SO_REUSE_RXTOALL - if (( -#if LWIP_IPV4 - broadcast || -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - ip6_addr_ismulticast(ip6_current_dest_addr()) || -#endif /* LWIP_IPV6 */ - ip_addr_ismulticast(ip_current_dest_addr())) && - ip_get_option(pcb, SOF_REUSEADDR)) { + if (ip_get_option(pcb, SOF_REUSEADDR) && + (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; @@ -395,32 +388,7 @@ udp_input(struct pbuf *p, struct netif *inp) if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && -#if LWIP_IPV6 - ((IP_IS_V6_VAL(mpcb->local_ip) && - (ip6_addr_ismulticast(ip6_current_dest_addr()) || - ip6_addr_cmp(ip_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) || - (!IP_IS_V6_VAL(mpcb->local_ip) && -#else /* LWIP_IPV6 */ - (( -#endif /* LWIP_IPV6 */ - (( -#if LWIP_IPV4 - !broadcast && -#endif /* LWIP_IPV4 */ - ip_addr_isany(&mpcb->local_ip)) || - ip_addr_cmp(&mpcb->local_ip, ip_current_dest_addr()) || -#if LWIP_IGMP - (ip_addr_isany(&pcb->local_ip) && ip_addr_ismulticast(ip_current_dest_addr())) || -#endif /* LWIP_IGMP */ -#if IP_SOF_BROADCAST_RECV - ( -#if LWIP_IPV4 - broadcast && -#endif /* LWIP_IPV4 */ - ip_get_option(mpcb, SOF_BROADCAST)))))) { -#else /* IP_SOF_BROADCAST_RECV */ - (broadcast))))) { -#endif /* IP_SOF_BROADCAST_RECV */ + (pcb_local_match(mpcb, inp, broadcast) != 0)) { /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; @@ -463,17 +431,7 @@ udp_input(struct pbuf *p, struct netif *inp) #if LWIP_ICMP || LWIP_ICMP6 /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ - if ( -#if LWIP_IPV4 - !broadcast && !ip_addr_ismulticast(ip_current_dest_addr()) -#if LWIP_IPV6 - && -#endif /* LWIP_IPV6 */ -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - !ip6_addr_ismulticast(ip6_current_dest_addr()) -#endif /* LWIP_IPV6 */ - ) { + if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { /* move payload pointer back to ip header */ pbuf_header_force(p, ip_current_header_tot_len() + UDP_HLEN); icmp_port_unreach(ip_current_is_v6(), p);