summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2013-01-26 00:57:29 +0000
committernp <np@FreeBSD.org>2013-01-26 00:57:29 +0000
commit9e6cd5d6e195151d900adda1e0ce34eeba9c8881 (patch)
tree40e943196c54952031d691186a2850d03e445f3c
parent637f5ddcf9c6ccb272a62bc7e63dc7dd4e4f4325 (diff)
downloadFreeBSD-src-9e6cd5d6e195151d900adda1e0ce34eeba9c8881.zip
FreeBSD-src-9e6cd5d6e195151d900adda1e0ce34eeba9c8881.tar.gz
Teach toe_l2_resolve to resolve IPv6 destinations too.
Reviewed by: bz@
-rw-r--r--sys/netinet/toecore.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c
index f7e2ba3..53d4778 100644
--- a/sys/netinet/toecore.c
+++ b/sys/netinet/toecore.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
+#include <netinet6/in6_var.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/nd6.h>
#define TCPSTATES
@@ -444,6 +445,68 @@ toe_route_redirect_event(void *arg __unused, struct rtentry *rt0,
return;
}
+#ifdef INET6
+/*
+ * XXX: no checks to verify that sa is really a neighbor because we assume it is
+ * the result of a route lookup and is on-link on the given ifp.
+ */
+static int
+toe_nd6_resolve(struct ifnet *ifp, struct sockaddr *sa, uint8_t *lladdr)
+{
+ struct llentry *lle;
+ struct sockaddr_in6 *sin6 = (void *)sa;
+ int rc, flags = 0;
+
+restart:
+ IF_AFDATA_RLOCK(ifp);
+ lle = lla_lookup(LLTABLE6(ifp), flags, sa);
+ IF_AFDATA_RUNLOCK(ifp);
+ if (lle == NULL) {
+ IF_AFDATA_LOCK(ifp);
+ lle = nd6_lookup(&sin6->sin6_addr, ND6_CREATE | ND6_EXCLUSIVE,
+ ifp);
+ IF_AFDATA_UNLOCK(ifp);
+ if (lle == NULL)
+ return (ENOMEM); /* Couldn't create entry in cache. */
+ lle->ln_state = ND6_LLINFO_INCOMPLETE;
+ nd6_llinfo_settimer_locked(lle,
+ (long)ND_IFINFO(ifp)->retrans * hz / 1000);
+ LLE_WUNLOCK(lle);
+
+ nd6_ns_output(ifp, NULL, &sin6->sin6_addr, NULL, 0);
+
+ return (EWOULDBLOCK);
+ }
+
+ if (lle->ln_state == ND6_LLINFO_STALE) {
+ if ((flags & LLE_EXCLUSIVE) == 0) {
+ LLE_RUNLOCK(lle);
+ flags |= LLE_EXCLUSIVE;
+ goto restart;
+ }
+
+ LLE_WLOCK_ASSERT(lle);
+
+ lle->la_asked = 0;
+ lle->ln_state = ND6_LLINFO_DELAY;
+ nd6_llinfo_settimer_locked(lle, (long)V_nd6_delay * hz);
+ }
+
+ if (lle->la_flags & LLE_VALID) {
+ memcpy(lladdr, &lle->ll_addr, ifp->if_addrlen);
+ rc = 0;
+ } else
+ rc = EWOULDBLOCK;
+
+ if (flags & LLE_EXCLUSIVE)
+ LLE_WUNLOCK(lle);
+ else
+ LLE_RUNLOCK(lle);
+
+ return (rc);
+}
+#endif
+
/*
* Returns 0 or EWOULDBLOCK on success (any other value is an error). 0 means
* lladdr and vtag are valid on return, EWOULDBLOCK means the TOE driver's
@@ -453,7 +516,9 @@ int
toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
uint8_t *lladdr, uint16_t *vtag)
{
+#ifdef INET
struct llentry *lle;
+#endif
int rc;
switch (sa->sa_family) {
@@ -464,7 +529,7 @@ toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
#endif
#ifdef INET6
case AF_INET6:
- rc = nd6_storelladdr(ifp, NULL, sa, lladdr, &lle);
+ rc = toe_nd6_resolve(ifp, sa, lladdr);
break;
#endif
default:
OpenPOWER on IntegriCloud