Mercurial > hg > dhcpcd
changeset 3522:3159a8c0ddb6 draft
RFC 3927 Section 2.5 says a defence of an address should ARP announce it.
This is unicast, whereas the default kernel action is to unicast a stock
reply, so the client that tried to claim the address will receive two replies.
Fixes [a19bb0eae6].
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Wed, 20 Apr 2016 08:29:08 +0000 |
| parents | 6fce403d7a88 |
| children | f574f4ded79b |
| files | arp.c arp.h ipv4ll.c |
| diffstat | 3 files changed, 21 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/arp.c Mon Apr 18 12:49:35 2016 +0000 +++ b/arp.c Wed Apr 20 08:29:08 2016 +0000 @@ -55,7 +55,7 @@ #define ARP_LEN \ (sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN)) -static ssize_t +ssize_t arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip) { uint8_t arp_buffer[ARP_LEN];
--- a/arp.h Mon Apr 18 12:49:35 2016 +0000 +++ b/arp.h Wed Apr 20 08:29:08 2016 +0000 @@ -77,6 +77,7 @@ ((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP]) #ifdef INET +ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t); void arp_report_conflicted(const struct arp_state *, const struct arp_msg *); void arp_announce(struct arp_state *); void arp_probe(struct arp_state *);
--- a/ipv4ll.c Mon Apr 18 12:49:35 2016 +0000 +++ b/ipv4ll.c Wed Apr 20 08:29:08 2016 +0000 @@ -259,26 +259,38 @@ if (astate->failed.s_addr == state->addr.s_addr) { struct timespec now, defend; - /* RFC 3927 Section 2.5 */ + /* RFC 3927 Section 2.5 says a defence should + * broadcast an ARP announcement. + * Because the kernel will also unicast a reply to the + * hardware address which requested the IP address + * the other IPv4LL client will receieve two ARP + * messages. + * If another conflict happens within DEFEND_INTERVAL + * then we must drop our address and negotiate a new one. */ defend.tv_sec = state->defend.tv_sec + DEFEND_INTERVAL; defend.tv_nsec = state->defend.tv_nsec; clock_gettime(CLOCK_MONOTONIC, &now); - if (timespeccmp(&defend, &now, >)) { + if (timespeccmp(&defend, &now, >)) logger(ifp->ctx, LOG_WARNING, "%s: IPv4LL %d second defence failed for %s", ifp->name, DEFEND_INTERVAL, inet_ntoa(state->addr)); - ipv4_deladdr(ifp, &state->addr, &inaddr_llmask, 1); - state->down = 1; - script_runreason(ifp, "IPV4LL"); - state->addr.s_addr = INADDR_ANY; - } else { + else if (arp_request(ifp, + state->addr.s_addr, state->addr.s_addr) == -1) + logger(ifp->ctx, LOG_ERR, + "%s: arp_request: %m", __func__); + else { logger(ifp->ctx, LOG_DEBUG, "%s: defended IPv4LL address %s", ifp->name, inet_ntoa(state->addr)); state->defend = now; return; } + + ipv4_deladdr(ifp, &state->addr, &inaddr_llmask, 1); + state->down = 1; + script_runreason(ifp, "IPV4LL"); + state->addr.s_addr = INADDR_ANY; } arp_cancel(astate);
