Index: sys/netinet/udp_usrreq.c =================================================================== --- sys/netinet/udp_usrreq.c +++ sys/netinet/udp_usrreq.c @@ -386,6 +386,28 @@ return (0); } +static bool +udp_inpcb_eq_ip_uh(struct inpcb *inp, struct ip *ip, struct udphdr *uh) +{ + if (inp->inp_lport != uh->uh_dport) + return false; +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) + return false; +#endif + if (inp->inp_laddr.s_addr != INADDR_ANY && + inp->inp_laddr.s_addr != ip->ip_dst.s_addr) + return false; + if (inp->inp_faddr.s_addr != INADDR_ANY && + inp->inp_faddr.s_addr != ip->ip_src.s_addr) + return false; + if (inp->inp_fport != 0 && + inp->inp_fport != uh->uh_sport) + return false; + + return true; +} + int udp_input(struct mbuf **mp, int *offp, int proto) { @@ -533,37 +555,17 @@ pcblist = udp_get_pcblist(proto); last = NULL; CK_LIST_FOREACH(inp, pcblist, inp_list) { - if (inp->inp_lport != uh->uh_dport) + if (!udp_inpcb_eq_ip_uh(inp, ip, uh)) continue; -#ifdef INET6 - if ((inp->inp_vflag & INP_IPV4) == 0) - continue; -#endif - if (inp->inp_laddr.s_addr != INADDR_ANY && - inp->inp_laddr.s_addr != ip->ip_dst.s_addr) - continue; - if (inp->inp_faddr.s_addr != INADDR_ANY && - inp->inp_faddr.s_addr != ip->ip_src.s_addr) - continue; - if (inp->inp_fport != 0 && - inp->inp_fport != uh->uh_sport) - continue; INP_RLOCK(inp); - if (__predict_false(inp->inp_flags2 & INP_FREED)) { + if (__predict_false(inp->inp_flags2 & INP_FREED) || !udp_inpcb_eq_ip_uh(inp, ip, uh)) { INP_RUNLOCK(inp); continue; } /* - * XXXRW: Because we weren't holding either the inpcb - * or the hash lock when we checked for a match - * before, we should probably recheck now that the - * inpcb lock is held. - */ - - /* * Handle socket delivery policy for any-source * and source-specific multicast. [RFC3678] */ Index: sys/netinet6/udp6_usrreq.c =================================================================== --- sys/netinet6/udp6_usrreq.c +++ sys/netinet6/udp6_usrreq.c @@ -201,6 +201,31 @@ return (0); } +static bool +udp6_inpcb_eq_ip6_uh(struct inpcb *inp, struct ip6_hdr *ip6, struct udphdr *uh) +{ + if ((inp->inp_vflag & INP_IPV6) == 0) + return false; + if (inp->inp_lport != uh->uh_dport) + return false; + if (inp->inp_fport != 0 && + inp->inp_fport != uh->uh_sport) + return false; + if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { + if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, + &ip6->ip6_dst)) + return false; + } + if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { + if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, + &ip6->ip6_src) || + inp->inp_fport != uh->uh_sport) + return false; + } + + return true; +} + int udp6_input(struct mbuf **mp, int *offp, int proto) { @@ -320,33 +345,10 @@ pcblist = udp_get_pcblist(nxt); last = NULL; CK_LIST_FOREACH(inp, pcblist, inp_list) { - if ((inp->inp_vflag & INP_IPV6) == 0) + if (!udp6_inpcb_eq_ip6_uh(inp, ip6, uh)) continue; - if (inp->inp_lport != uh->uh_dport) - continue; - if (inp->inp_fport != 0 && - inp->inp_fport != uh->uh_sport) - continue; - if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { - if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, - &ip6->ip6_dst)) - continue; - } - if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { - if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, - &ip6->ip6_src) || - inp->inp_fport != uh->uh_sport) - continue; - } /* - * XXXRW: Because we weren't holding either the inpcb - * or the hash lock when we checked for a match - * before, we should probably recheck now that the - * inpcb lock is (supposed to be) held. - */ - - /* * Handle socket delivery policy for any-source * and source-specific multicast. [RFC3678] */ @@ -356,7 +358,7 @@ int blocked; INP_RLOCK(inp); - if (__predict_false(inp->inp_flags2 & INP_FREED)) { + if (__predict_false(inp->inp_flags2 & INP_FREED) || !udp6_inpcb_eq_ip6_uh(inp, ip6, uh)) { INP_RUNLOCK(inp); continue; }