Similar to IPv6.
However, this code will just live in this branch and go no futher
because it's not tennable. Modern DHCP servers won't let you
assign the same IP to different hardware addresses.
Some kernels announce ARP after a link flap giving a large window
where requests could goto a valid address but the wrong one.
What IP address sharing set out to achieve was a poor mans link
aggregation for OSs that lacked another way of doing it ....
Well, with NetBSD finally getting lagg(4), all supported OS's
now have this so there is no more need for it in dhcpcd.
arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
{
struct arp_state *astate;
+ struct ipv4_addr *ia4;
if (ifp->flags & IFF_NOARP || !(ifp->options->options & DHCPCD_ARP))
return NULL;
+ ia4 = ipv4_iffindaddr(ifp, ia, NULL);
+ if (ia4->flags & IPV4_AF_ADVERTISED)
+ return NULL;
astate = arp_find(ifp, ia);
if (astate == NULL) {
return NULL;
astate->announced_cb = arp_free;
}
+ ia4->flags |= IPV4_AF_ADVERTISED;
arp_announce(astate);
return astate;
}
arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
{
struct interface *ifp, *iff = NULL;
- struct ipv4_addr *iap;
+ struct ipv4_addr *iap, *iaf = NULL;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
- if (!ifp->active || !if_is_link_up(ifp))
- continue;
iap = ipv4_iffindaddr(ifp, ia, NULL);
if (iap == NULL)
continue;
+
+ if (!ifp->active || !if_is_link_up(ifp))
+ continue;
#ifdef IN_IFF_NOTUSEABLE
if (iap->addr_flags & IN_IFF_NOTUSEABLE)
continue;
if (iff != NULL && iff->metric < ifp->metric)
continue;
iff = ifp;
+ iaf = iap;
}
- if (iff == NULL)
+ if (iaf == NULL || iaf->flags & IPV4_AF_ADVERTISED)
return NULL;
- return arp_ifannounceaddr(iff, ia);
+ TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+ iap = ipv4_iffindaddr(ifp, ia, NULL);
+ if (iap == NULL)
+ continue;
+ iap->flags &= ~IPV4_AF_ADVERTISED;
+ }
+
+ return arp_ifannounceaddr(iff, &iaf->addr);
}
struct arp_state *
#ifdef ARP
/* Announce the preferred address to
* kick ARP caches. */
- arp_announceaddr(ifp->ctx,&lease->addr);
+ arp_announceaddr(ifp->ctx, &lease->addr);
#endif
}
script_runreason(ifp, state->reason);
free(ia);
}
+void
+ipv4_start(struct interface *ifp)
+{
+#ifdef ARP
+ struct ipv4_state *state;
+ struct ipv4_addr *ia;
+
+ if (ifp == NULL || (state = IPV4_STATE(ifp)) == NULL)
+ return;
+
+ /* Clear advertised */
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ ia->flags &= ~IPV4_AF_ADVERTISED;
+ }
+#endif
+}
+
void
ipv4_free(struct interface *ifp)
{
#define IPV4_AF_STALE (1U << 0)
#define IPV4_AF_NEW (1U << 1)
+#define IPV4_AF_ADVERTISED (1U << 2)
#define IPV4_ADDR_EQ(a1, a2) ((a1) && (a1)->addr.s_addr == (a2)->addr.s_addr)
#define IPV4_MASK1_EQ(a1, a2) ((a1) && (a1)->mask.s_addr == (a2)->mask.s_addr)
struct interface *ifp;
struct ipv6_state *state;
struct ipv6_addr *iap, *iaf;
- bool found_another = false;
struct nd_neighbor_advert *na;
if (IN6_IS_ADDR_MULTICAST(&ia->addr))
if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
continue;
- if (iaf != NULL)
- found_another = true;
-
/* Don't advertise what we can't use. */
if (iap->prefix_vltime == 0 ||
iap->addr_flags & IN6_IFF_NOTUSEABLE ||
+ !ifp->active ||
!if_is_link_up(ifp))
continue;
return;
/* Now cancel any other advertisements for the same address. */
- if (found_another) {
- TAILQ_FOREACH(ifp, ctx->ifaces, next) {
- state = IPV6_STATE(ifp);
- if (state == NULL)
- continue;
+ TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+ state = IPV6_STATE(ifp);
+ if (state == NULL)
+ continue;
- TAILQ_FOREACH(iap, &state->addrs, next) {
- if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
- continue;
+ TAILQ_FOREACH(iap, &state->addrs, next) {
+ if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
+ continue;
- iap->flags &= ~IPV6_AF_ADVERTISED;
- eloop_timeout_delete(ctx->eloop,
- ipv6nd_sendadvertisement, iap);
- }
+ iap->flags &= ~IPV6_AF_ADVERTISED;
+ eloop_timeout_delete(ctx->eloop,
+ ipv6nd_sendadvertisement, iap);
}
- } else {
- eloop_timeout_delete(ctx->eloop,
- ipv6nd_sendadvertisement, iaf);
}
/* Make the packet. */