summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/udp6_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/udp6_usrreq.c')
-rw-r--r--freebsd/sys/netinet6/udp6_usrreq.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/freebsd/sys/netinet6/udp6_usrreq.c b/freebsd/sys/netinet6/udp6_usrreq.c
index e0fcd06d..270b4880 100644
--- a/freebsd/sys/netinet6/udp6_usrreq.c
+++ b/freebsd/sys/netinet6/udp6_usrreq.c
@@ -744,9 +744,24 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
* - when we are not bound to an address and source port (it is
* in6_pcbsetport() which will require the write lock).
*/
+retry:
if (sin6 == NULL || (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
inp->inp_lport == 0)) {
INP_WLOCK(inp);
+ /*
+ * In case we lost a race and another thread bound addr/port
+ * on the inp we cannot keep the wlock (which still would be
+ * fine) as further down, based on these values we make
+ * decisions for the pcbinfo lock. If the locks are not in
+ * synch the assertions on unlock will fire, hence we go for
+ * one retry loop.
+ */
+ if (sin6 != NULL &&
+ (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ||
+ inp->inp_lport != 0)) {
+ INP_WUNLOCK(inp);
+ goto retry;
+ }
unlock_inp = UH_WLOCKED;
} else {
INP_RLOCK(inp);