summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphilip <philip@FreeBSD.org>2008-08-18 09:06:11 +0000
committerphilip <philip@FreeBSD.org>2008-08-18 09:06:11 +0000
commit3f18959cf6cf4543a19d1073d6f53b142e2f46e7 (patch)
tree8194aa1c4207987a4cd8bf58c1716ed53a2b39b8
parent0d74400a62306625ffa8bb35cba7925b956ec864 (diff)
downloadFreeBSD-src-3f18959cf6cf4543a19d1073d6f53b142e2f46e7.zip
FreeBSD-src-3f18959cf6cf4543a19d1073d6f53b142e2f46e7.tar.gz
Fix ARP in bridging scenarios where the bridge shares its
MAC address with one of its members (see my r180140). Pointy hat to: philip Submitted by: Eygene Ryabinkin <rea-fbsd@codelabs.ru> MFC after: 3 days
-rw-r--r--sys/netinet/if_ether.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 6f489a2..558db3b 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -592,7 +592,7 @@ in_arpinput(struct mbuf *m)
u_int8_t *enaddr = NULL;
int op, rif_len;
int req_len;
- int bridged = 0;
+ int bridged = 0, is_bridge = 0;
u_int fibnum;
u_int goodfib = 0;
int firstpass = 1;
@@ -606,6 +606,8 @@ in_arpinput(struct mbuf *m)
if (ifp->if_bridge)
bridged = 1;
+ if (ifp->if_type == IFT_BRIDGE)
+ is_bridge = 1;
req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) {
@@ -646,6 +648,27 @@ in_arpinput(struct mbuf *m)
(ia->ia_ifp == ifp)) &&
isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
goto match;
+
+#define BDG_MEMBER_MATCHES_ARP(addr, ifp, ia) \
+ (ia->ia_ifp->if_bridge == ifp->if_softc && \
+ !bcmp(IF_LLADDR(ia->ia_ifp), IF_LLADDR(ifp), ifp->if_addrlen) && \
+ addr == ia->ia_addr.sin_addr.s_addr)
+ /*
+ * Check the case when bridge shares its MAC address with
+ * some of its children, so packets are claimed by bridge
+ * itself (bridge_input() does it first), but they are really
+ * meant to be destined to the bridge member.
+ */
+ if (is_bridge) {
+ LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) {
+ if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) {
+ ifp = ia->ia_ifp;
+ goto match;
+ }
+ }
+ }
+#undef BDG_MEMBER_MATCHES_ARP
+
/*
* No match, use the first inet address on the receive interface
* as a dummy address for the rest of the function.
OpenPOWER on IntegriCloud