summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/in.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/in.c')
-rw-r--r--freebsd/sys/netinet/in.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/freebsd/sys/netinet/in.c b/freebsd/sys/netinet/in.c
index db1ebda0..ae32c8d9 100644
--- a/freebsd/sys/netinet/in.c
+++ b/freebsd/sys/netinet/in.c
@@ -1382,15 +1382,13 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add
IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
KASSERT(l3addr->sa_family == AF_INET,
("sin_family %d", l3addr->sa_family));
- lle = in_lltable_find_dst(llt, sin->sin_addr);
+ KASSERT((flags & (LLE_UNLOCKED | LLE_EXCLUSIVE)) !=
+ (LLE_UNLOCKED | LLE_EXCLUSIVE),
+ ("wrong lle request flags: %#x", flags));
+ lle = in_lltable_find_dst(llt, sin->sin_addr);
if (lle == NULL)
return (NULL);
-
- KASSERT((flags & (LLE_UNLOCKED|LLE_EXCLUSIVE)) !=
- (LLE_UNLOCKED|LLE_EXCLUSIVE),("wrong lle request flags: 0x%X",
- flags));
-
if (flags & LLE_UNLOCKED)
return (lle);
@@ -1399,6 +1397,17 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add
else
LLE_RLOCK(lle);
+ /*
+ * If the afdata lock is not held, the LLE may have been unlinked while
+ * we were blocked on the LLE lock. Check for this case.
+ */
+ if (__predict_false((lle->la_flags & LLE_LINKED) == 0)) {
+ if (flags & LLE_EXCLUSIVE)
+ LLE_WUNLOCK(lle);
+ else
+ LLE_RUNLOCK(lle);
+ return (NULL);
+ }
return (lle);
}