summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2012-01-08 17:25:15 +0000
committerglebius <glebius@FreeBSD.org>2012-01-08 17:25:15 +0000
commitaab03c16b7e59caefceff3871d99e75f822250ed (patch)
tree7359369285f8f12a55d14df0723585b71aa3a600
parentc48f3c200231b80bc06adec794b0b940a2270f1f (diff)
downloadFreeBSD-src-aab03c16b7e59caefceff3871d99e75f822250ed.zip
FreeBSD-src-aab03c16b7e59caefceff3871d99e75f822250ed.tar.gz
Make it possible to use alternative source hardware address
in the ARP datagram generated by arprequest(). If caller doesn't supply the address, then it is either picked from CARP or hardware address of the interface is taken. While here, make several minor fixes: - Hold IF_ADDR_RLOCK(ifp) while traversing address list. - Remove not true comment. - Access internet address and mask via in_ifaddr fields, rather than ifaddr.
-rw-r--r--sys/netinet/if_ether.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 4544fbe..a1fb3ca 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -211,29 +211,41 @@ arprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip,
struct mbuf *m;
struct arphdr *ah;
struct sockaddr sa;
+ u_char *carpaddr = NULL;
if (sip == NULL) {
- /* XXX don't believe this can happen (or explain why) */
/*
* The caller did not supply a source address, try to find
* a compatible one among those assigned to this interface.
*/
struct ifaddr *ifa;
+ IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- if (!ifa->ifa_addr ||
- ifa->ifa_addr->sa_family != AF_INET)
+ if (ifa->ifa_addr->sa_family != AF_INET)
continue;
- sip = &SIN(ifa->ifa_addr)->sin_addr;
+
+ if (ifa->ifa_carp) {
+ if ((*carp_iamatch_p)(ifa, &carpaddr) == 0)
+ continue;
+ sip = &IA_SIN(ifa)->sin_addr;
+ } else {
+ carpaddr = NULL;
+ sip = &IA_SIN(ifa)->sin_addr;
+ }
+
if (0 == ((sip->s_addr ^ tip->s_addr) &
- SIN(ifa->ifa_netmask)->sin_addr.s_addr) )
+ IA_MASKSIN(ifa)->sin_addr.s_addr))
break; /* found it. */
}
+ IF_ADDR_RUNLOCK(ifp);
if (sip == NULL) {
printf("%s: cannot find matching address\n", __func__);
return;
}
}
+ if (enaddr == NULL)
+ enaddr = carpaddr ? carpaddr : (u_char *)IF_LLADDR(ifp);
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
return;
@@ -328,9 +340,7 @@ retry:
*/
if (!(la->la_flags & LLE_STATIC) &&
time_uptime + la->la_preempt > la->la_expire) {
- arprequest(ifp, NULL,
- &SIN(dst)->sin_addr, IF_LLADDR(ifp));
-
+ arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
la->la_preempt--;
}
@@ -406,8 +416,7 @@ retry:
LLE_REMREF(la);
la->la_asked++;
LLE_WUNLOCK(la);
- arprequest(ifp, NULL, &SIN(dst)->sin_addr,
- IF_LLADDR(ifp));
+ arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
return (error);
}
done:
OpenPOWER on IntegriCloud