xref: /dragonfly/contrib/dhcpcd/src/arp.c (revision 54175cef)
18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * dhcpcd - ARP handler
480aa9461SRoy Marples  * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI  * All rights reserved
67827cba2SAaron LI 
77827cba2SAaron LI  * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI  * modification, are permitted provided that the following conditions
97827cba2SAaron LI  * are met:
107827cba2SAaron LI  * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI  *    documentation and/or other materials provided with the distribution.
157827cba2SAaron LI  *
167827cba2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI  * SUCH DAMAGE.
277827cba2SAaron LI  */
287827cba2SAaron LI 
297827cba2SAaron LI #include <sys/socket.h>
307827cba2SAaron LI #include <sys/types.h>
317827cba2SAaron LI 
327827cba2SAaron LI #include <arpa/inet.h>
337827cba2SAaron LI 
347827cba2SAaron LI #include <net/if.h>
357827cba2SAaron LI #include <netinet/in.h>
367827cba2SAaron LI #include <netinet/if_ether.h>
377827cba2SAaron LI 
387827cba2SAaron LI #include <errno.h>
397827cba2SAaron LI #include <stdlib.h>
408d36e1dfSRoy Marples #include <stdio.h>
417827cba2SAaron LI #include <string.h>
427827cba2SAaron LI #include <unistd.h>
437827cba2SAaron LI 
446e63cc1fSRoy Marples #define ELOOP_QUEUE	ELOOP_ARP
457827cba2SAaron LI #include "config.h"
467827cba2SAaron LI #include "arp.h"
477827cba2SAaron LI #include "bpf.h"
487827cba2SAaron LI #include "ipv4.h"
497827cba2SAaron LI #include "common.h"
507827cba2SAaron LI #include "dhcpcd.h"
517827cba2SAaron LI #include "eloop.h"
527827cba2SAaron LI #include "if.h"
537827cba2SAaron LI #include "if-options.h"
547827cba2SAaron LI #include "ipv4ll.h"
557827cba2SAaron LI #include "logerr.h"
566e63cc1fSRoy Marples #include "privsep.h"
577827cba2SAaron LI 
587827cba2SAaron LI #if defined(ARP)
597827cba2SAaron LI #define ARP_LEN								\
606e63cc1fSRoy Marples 	(FRAMEHDRLEN_MAX +						\
616e63cc1fSRoy Marples 	 sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
627827cba2SAaron LI 
637827cba2SAaron LI /* ARP debugging can be quite noisy. Enable this for more noise! */
647827cba2SAaron LI //#define	ARP_DEBUG
657827cba2SAaron LI 
667827cba2SAaron LI /* Assert the correct structure size for on wire */
677827cba2SAaron LI __CTASSERT(sizeof(struct arphdr) == 8);
687827cba2SAaron LI 
698d36e1dfSRoy Marples static ssize_t
arp_request(const struct arp_state * astate,const struct in_addr * sip)70d4fb1e02SRoy Marples arp_request(const struct arp_state *astate,
71d4fb1e02SRoy Marples     const struct in_addr *sip)
727827cba2SAaron LI {
73d4fb1e02SRoy Marples 	const struct interface *ifp = astate->iface;
74d4fb1e02SRoy Marples 	const struct in_addr *tip = &astate->addr;
757827cba2SAaron LI 	uint8_t arp_buffer[ARP_LEN];
767827cba2SAaron LI 	struct arphdr ar;
777827cba2SAaron LI 	size_t len;
787827cba2SAaron LI 	uint8_t *p;
797827cba2SAaron LI 
80d4fb1e02SRoy Marples 	ar.ar_hrd = htons(ifp->hwtype);
817827cba2SAaron LI 	ar.ar_pro = htons(ETHERTYPE_IP);
827827cba2SAaron LI 	ar.ar_hln = ifp->hwlen;
838d36e1dfSRoy Marples 	ar.ar_pln = sizeof(tip->s_addr);
847827cba2SAaron LI 	ar.ar_op = htons(ARPOP_REQUEST);
857827cba2SAaron LI 
867827cba2SAaron LI 	p = arp_buffer;
877827cba2SAaron LI 	len = 0;
887827cba2SAaron LI 
897827cba2SAaron LI #define CHECK(fun, b, l)						\
907827cba2SAaron LI 	do {								\
917827cba2SAaron LI 		if (len + (l) > sizeof(arp_buffer))			\
927827cba2SAaron LI 			goto eexit;					\
937827cba2SAaron LI 		fun(p, (b), (l));					\
947827cba2SAaron LI 		p += (l);						\
957827cba2SAaron LI 		len += (l);						\
967827cba2SAaron LI 	} while (/* CONSTCOND */ 0)
977827cba2SAaron LI #define APPEND(b, l)	CHECK(memcpy, b, l)
987827cba2SAaron LI #define ZERO(l)		CHECK(memset, 0, l)
997827cba2SAaron LI 
1007827cba2SAaron LI 	APPEND(&ar, sizeof(ar));
1017827cba2SAaron LI 	APPEND(ifp->hwaddr, ifp->hwlen);
1028d36e1dfSRoy Marples 	if (sip != NULL)
1038d36e1dfSRoy Marples 		APPEND(&sip->s_addr, sizeof(sip->s_addr));
1048d36e1dfSRoy Marples 	else
1058d36e1dfSRoy Marples 		ZERO(sizeof(tip->s_addr));
1067827cba2SAaron LI 	ZERO(ifp->hwlen);
1078d36e1dfSRoy Marples 	APPEND(&tip->s_addr, sizeof(tip->s_addr));
1087827cba2SAaron LI 
1096e63cc1fSRoy Marples #ifdef PRIVSEP
1106e63cc1fSRoy Marples 	if (ifp->ctx->options & DHCPCD_PRIVSEP)
111d4fb1e02SRoy Marples 		return ps_bpf_sendarp(ifp, tip, arp_buffer, len);
1126e63cc1fSRoy Marples #endif
1136e63cc1fSRoy Marples 	/* Note that well formed ethernet will add extra padding
1146e63cc1fSRoy Marples 	 * to ensure that the packet is at least 60 bytes (64 including FCS). */
115d4fb1e02SRoy Marples 	return bpf_send(astate->bpf, ETHERTYPE_ARP, arp_buffer, len);
1167827cba2SAaron LI 
1177827cba2SAaron LI eexit:
1187827cba2SAaron LI 	errno = ENOBUFS;
1197827cba2SAaron LI 	return -1;
1207827cba2SAaron LI }
1217827cba2SAaron LI 
1227827cba2SAaron LI static void
arp_report_conflicted(const struct arp_state * astate,const struct arp_msg * amsg)1238d36e1dfSRoy Marples arp_report_conflicted(const struct arp_state *astate,
1248d36e1dfSRoy Marples     const struct arp_msg *amsg)
1258d36e1dfSRoy Marples {
1266e63cc1fSRoy Marples 	char abuf[HWADDR_LEN * 3];
1276e63cc1fSRoy Marples 	char fbuf[HWADDR_LEN * 3];
1288d36e1dfSRoy Marples 
1298d36e1dfSRoy Marples 	if (amsg == NULL) {
1308d36e1dfSRoy Marples 		logerrx("%s: DAD detected %s",
1318d36e1dfSRoy Marples 		    astate->iface->name, inet_ntoa(astate->addr));
1328d36e1dfSRoy Marples 		return;
1338d36e1dfSRoy Marples 	}
1348d36e1dfSRoy Marples 
1356e63cc1fSRoy Marples 	hwaddr_ntoa(amsg->sha, astate->iface->hwlen, abuf, sizeof(abuf));
1366e63cc1fSRoy Marples 	if (bpf_frame_header_len(astate->iface) == 0) {
137d4fb1e02SRoy Marples 		logwarnx("%s: %s claims %s",
1386e63cc1fSRoy Marples 		    astate->iface->name, abuf, inet_ntoa(astate->addr));
1396e63cc1fSRoy Marples 		return;
1406e63cc1fSRoy Marples 	}
1416e63cc1fSRoy Marples 
142d4fb1e02SRoy Marples 	logwarnx("%s: %s(%s) claims %s",
1436e63cc1fSRoy Marples 	    astate->iface->name, abuf,
1446e63cc1fSRoy Marples 	    hwaddr_ntoa(amsg->fsha, astate->iface->hwlen, fbuf, sizeof(fbuf)),
1458d36e1dfSRoy Marples 	    inet_ntoa(astate->addr));
1468d36e1dfSRoy Marples }
1478d36e1dfSRoy Marples 
1488d36e1dfSRoy Marples static void
arp_found(struct arp_state * astate,const struct arp_msg * amsg)1498d36e1dfSRoy Marples arp_found(struct arp_state *astate, const struct arp_msg *amsg)
1508d36e1dfSRoy Marples {
1518d36e1dfSRoy Marples 	struct interface *ifp;
1521b3b16a2SRoy Marples 	struct ipv4_addr *ia;
1538d36e1dfSRoy Marples #ifndef KERNEL_RFC5227
1546e63cc1fSRoy Marples 	struct timespec now;
1558d36e1dfSRoy Marples #endif
1568d36e1dfSRoy Marples 
1578d36e1dfSRoy Marples 	arp_report_conflicted(astate, amsg);
1588d36e1dfSRoy Marples 	ifp = astate->iface;
1598d36e1dfSRoy Marples 
1608d36e1dfSRoy Marples 	/* If we haven't added the address we're doing a probe. */
1618d36e1dfSRoy Marples 	ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
1628d36e1dfSRoy Marples 	if (ia == NULL) {
1638d36e1dfSRoy Marples 		if (astate->found_cb != NULL)
1648d36e1dfSRoy Marples 			astate->found_cb(astate, amsg);
1658d36e1dfSRoy Marples 		return;
1668d36e1dfSRoy Marples 	}
1678d36e1dfSRoy Marples 
1688d36e1dfSRoy Marples #ifndef KERNEL_RFC5227
1698d36e1dfSRoy Marples 	/* RFC 3927 Section 2.5 says a defence should
1708d36e1dfSRoy Marples 	 * broadcast an ARP announcement.
1718d36e1dfSRoy Marples 	 * Because the kernel will also unicast a reply to the
1728d36e1dfSRoy Marples 	 * hardware address which requested the IP address
1738d36e1dfSRoy Marples 	 * the other IPv4LL client will receieve two ARP
1748d36e1dfSRoy Marples 	 * messages.
1758d36e1dfSRoy Marples 	 * If another conflict happens within DEFEND_INTERVAL
176*54175cefSRoy Marples 	 * then we must drop our address and negotiate a new one.
177*54175cefSRoy Marples 	 * If DHCPCD_ARP_PERSISTDEFENCE is set, that enables
178*54175cefSRoy Marples 	 * RFC5227 section 2.4.c behaviour. Upon conflict
179*54175cefSRoy Marples 	 * detection, the host records the time that the
180*54175cefSRoy Marples 	 * conflicting ARP packet was received, and then
181*54175cefSRoy Marples 	 * broadcasts one single ARP Announcement. The host then
182*54175cefSRoy Marples 	 * continues to use the address normally. All further
183*54175cefSRoy Marples 	 * conflict notifications within the DEFEND_INTERVAL are
184*54175cefSRoy Marples 	 * ignored. */
1858d36e1dfSRoy Marples 	clock_gettime(CLOCK_MONOTONIC, &now);
1866e63cc1fSRoy Marples 	if (timespecisset(&astate->defend) &&
1876e63cc1fSRoy Marples 	    eloop_timespec_diff(&now, &astate->defend, NULL) < DEFEND_INTERVAL)
188*54175cefSRoy Marples 	{
1898d36e1dfSRoy Marples 		logwarnx("%s: %d second defence failed for %s",
1908d36e1dfSRoy Marples 		    ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr));
191*54175cefSRoy Marples 		if (ifp->options->options & DHCPCD_ARP_PERSISTDEFENCE)
192*54175cefSRoy Marples 			return;
193*54175cefSRoy Marples 	}
194d4fb1e02SRoy Marples 	else if (arp_request(astate, &astate->addr) == -1)
1958d36e1dfSRoy Marples 		logerr(__func__);
1968d36e1dfSRoy Marples 	else {
1978d36e1dfSRoy Marples 		logdebugx("%s: defended address %s",
1988d36e1dfSRoy Marples 		    ifp->name, inet_ntoa(astate->addr));
1998d36e1dfSRoy Marples 		astate->defend = now;
2008d36e1dfSRoy Marples 		return;
2018d36e1dfSRoy Marples 	}
2028d36e1dfSRoy Marples #endif
2038d36e1dfSRoy Marples 
2048d36e1dfSRoy Marples 	if (astate->defend_failed_cb != NULL)
2058d36e1dfSRoy Marples 		astate->defend_failed_cb(astate);
2068d36e1dfSRoy Marples }
2078d36e1dfSRoy Marples 
2081b3b16a2SRoy Marples static bool
arp_validate(const struct interface * ifp,struct arphdr * arp)2091b3b16a2SRoy Marples arp_validate(const struct interface *ifp, struct arphdr *arp)
2101b3b16a2SRoy Marples {
2111b3b16a2SRoy Marples 
212d4fb1e02SRoy Marples 	/* Address type must match */
213d4fb1e02SRoy Marples 	if (arp->ar_hrd != htons(ifp->hwtype))
2141b3b16a2SRoy Marples 		return false;
2151b3b16a2SRoy Marples 
2161b3b16a2SRoy Marples 	/* Protocol must be IP. */
2171b3b16a2SRoy Marples 	if (arp->ar_pro != htons(ETHERTYPE_IP))
2181b3b16a2SRoy Marples 		return false;
2191b3b16a2SRoy Marples 
2201b3b16a2SRoy Marples 	/* lladdr length matches */
2211b3b16a2SRoy Marples 	if (arp->ar_hln != ifp->hwlen)
2221b3b16a2SRoy Marples 		return false;
2231b3b16a2SRoy Marples 
2241b3b16a2SRoy Marples 	/* Protocol length must match in_addr_t */
2251b3b16a2SRoy Marples 	if (arp->ar_pln != sizeof(in_addr_t))
2261b3b16a2SRoy Marples 		return false;
2271b3b16a2SRoy Marples 
2281b3b16a2SRoy Marples 	/* Only these types are recognised */
2291b3b16a2SRoy Marples 	if (arp->ar_op != htons(ARPOP_REPLY) &&
2301b3b16a2SRoy Marples 	    arp->ar_op != htons(ARPOP_REQUEST))
2311b3b16a2SRoy Marples 		return false;
2321b3b16a2SRoy Marples 
2331b3b16a2SRoy Marples 	return true;
2341b3b16a2SRoy Marples }
2351b3b16a2SRoy Marples 
2366e63cc1fSRoy Marples void
arp_packet(struct interface * ifp,uint8_t * data,size_t len,unsigned int bpf_flags)237d4fb1e02SRoy Marples arp_packet(struct interface *ifp, uint8_t *data, size_t len,
238d4fb1e02SRoy Marples     unsigned int bpf_flags)
2397827cba2SAaron LI {
2406e63cc1fSRoy Marples 	size_t fl = bpf_frame_header_len(ifp), falen;
2417827cba2SAaron LI 	const struct interface *ifn;
2427827cba2SAaron LI 	struct arphdr ar;
2437827cba2SAaron LI 	struct arp_msg arm;
2447827cba2SAaron LI 	const struct iarp_state *state;
2457827cba2SAaron LI 	struct arp_state *astate, *astaten;
2467827cba2SAaron LI 	uint8_t *hw_s, *hw_t;
24780aa9461SRoy Marples #ifndef KERNEL_RFC5227
24880aa9461SRoy Marples 	bool is_probe;
24980aa9461SRoy Marples #endif /* KERNEL_RFC5227 */
2507827cba2SAaron LI 
2516e63cc1fSRoy Marples 	/* Copy the frame header source and destination out */
2526e63cc1fSRoy Marples 	memset(&arm, 0, sizeof(arm));
2536e63cc1fSRoy Marples 	if (fl != 0) {
2546e63cc1fSRoy Marples 		hw_s = bpf_frame_header_src(ifp, data, &falen);
2556e63cc1fSRoy Marples 		if (hw_s != NULL && falen <= sizeof(arm.fsha))
2566e63cc1fSRoy Marples 			memcpy(arm.fsha, hw_s, falen);
2576e63cc1fSRoy Marples 		hw_t = bpf_frame_header_dst(ifp, data, &falen);
2586e63cc1fSRoy Marples 		if (hw_t != NULL && falen <= sizeof(arm.ftha))
2596e63cc1fSRoy Marples 			memcpy(arm.ftha, hw_t, falen);
2606e63cc1fSRoy Marples 
2616e63cc1fSRoy Marples 		/* Skip past the frame header */
2626e63cc1fSRoy Marples 		data += fl;
2636e63cc1fSRoy Marples 		len -= fl;
2646e63cc1fSRoy Marples 	}
2656e63cc1fSRoy Marples 
2667827cba2SAaron LI 	/* We must have a full ARP header */
2677827cba2SAaron LI 	if (len < sizeof(ar))
2687827cba2SAaron LI 		return;
2697827cba2SAaron LI 	memcpy(&ar, data, sizeof(ar));
2707827cba2SAaron LI 
2711b3b16a2SRoy Marples 	if (!arp_validate(ifp, &ar)) {
2721b3b16a2SRoy Marples #ifdef BPF_DEBUG
2731b3b16a2SRoy Marples 		logerrx("%s: ARP BPF validation failure", ifp->name);
2747827cba2SAaron LI #endif
2751b3b16a2SRoy Marples 		return;
2761b3b16a2SRoy Marples 	}
2777827cba2SAaron LI 
2787827cba2SAaron LI 	/* Get pointers to the hardware addresses */
2797827cba2SAaron LI 	hw_s = data + sizeof(ar);
2807827cba2SAaron LI 	hw_t = hw_s + ar.ar_hln + ar.ar_pln;
2817827cba2SAaron LI 	/* Ensure we got all the data */
2827827cba2SAaron LI 	if ((size_t)((hw_t + ar.ar_hln + ar.ar_pln) - data) > len)
2837827cba2SAaron LI 		return;
2847827cba2SAaron LI 	/* Ignore messages from ourself */
2857827cba2SAaron LI 	TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
2867827cba2SAaron LI 		if (ar.ar_hln == ifn->hwlen &&
2877827cba2SAaron LI 		    memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
2887827cba2SAaron LI 			break;
2897827cba2SAaron LI 	}
2907827cba2SAaron LI 	if (ifn) {
2917827cba2SAaron LI #ifdef ARP_DEBUG
2927827cba2SAaron LI 		logdebugx("%s: ignoring ARP from self", ifp->name);
2937827cba2SAaron LI #endif
2947827cba2SAaron LI 		return;
2957827cba2SAaron LI 	}
2967827cba2SAaron LI 	/* Copy out the HW and IP addresses */
2977827cba2SAaron LI 	memcpy(&arm.sha, hw_s, ar.ar_hln);
2987827cba2SAaron LI 	memcpy(&arm.sip.s_addr, hw_s + ar.ar_hln, ar.ar_pln);
2997827cba2SAaron LI 	memcpy(&arm.tha, hw_t, ar.ar_hln);
3007827cba2SAaron LI 	memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
3017827cba2SAaron LI 
30280aa9461SRoy Marples #ifndef KERNEL_RFC5227
30380aa9461SRoy Marples 	/* During ARP probe the 'sender hardware address' MUST contain the hardware
30480aa9461SRoy Marples 	 * address of the interface sending the packet. RFC5227, 1.1 */
30580aa9461SRoy Marples 	is_probe = ar.ar_op == htons(ARPOP_REQUEST) && IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
30680aa9461SRoy Marples 	    bpf_flags & BPF_BCAST;
30780aa9461SRoy Marples 	if (is_probe && falen > 0 && (falen != ar.ar_hln ||
30880aa9461SRoy Marples 	    memcmp(&arm.sha, &arm.fsha, ar.ar_hln))) {
30980aa9461SRoy Marples 		char abuf[HWADDR_LEN * 3];
31080aa9461SRoy Marples 		char fbuf[HWADDR_LEN * 3];
31180aa9461SRoy Marples 		hwaddr_ntoa(&arm.sha, ar.ar_hln, abuf, sizeof(abuf));
31280aa9461SRoy Marples 		hwaddr_ntoa(&arm.fsha, falen, fbuf, sizeof(fbuf));
31380aa9461SRoy Marples 		logwarnx("%s: invalid ARP probe, sender hw address mismatch (%s, %s)",
31480aa9461SRoy Marples 		    ifp->name, abuf, fbuf);
31580aa9461SRoy Marples 		return;
31680aa9461SRoy Marples 	}
31780aa9461SRoy Marples #endif /* KERNEL_RFC5227 */
31880aa9461SRoy Marples 
3198d36e1dfSRoy Marples 	/* Match the ARP probe to our states.
3208d36e1dfSRoy Marples 	 * Ignore Unicast Poll, RFC1122. */
3217827cba2SAaron LI 	state = ARP_CSTATE(ifp);
3226e63cc1fSRoy Marples 	if (state == NULL)
3236e63cc1fSRoy Marples 		return;
3247827cba2SAaron LI 	TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
3258d36e1dfSRoy Marples 		if (IN_ARE_ADDR_EQUAL(&arm.sip, &astate->addr) ||
3268d36e1dfSRoy Marples 		    (IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
3278d36e1dfSRoy Marples 		    IN_ARE_ADDR_EQUAL(&arm.tip, &astate->addr) &&
328d4fb1e02SRoy Marples 		    bpf_flags & BPF_BCAST))
3298d36e1dfSRoy Marples 			arp_found(astate, &arm);
3307827cba2SAaron LI 	}
3317827cba2SAaron LI }
3327827cba2SAaron LI 
3338d36e1dfSRoy Marples static void
arp_read(void * arg,unsigned short events)33480aa9461SRoy Marples arp_read(void *arg, unsigned short events)
3357827cba2SAaron LI {
336d4fb1e02SRoy Marples 	struct arp_state *astate = arg;
337d4fb1e02SRoy Marples 	struct bpf *bpf = astate->bpf;
338d4fb1e02SRoy Marples 	struct interface *ifp = astate->iface;
3397827cba2SAaron LI 	uint8_t buf[ARP_LEN];
3407827cba2SAaron LI 	ssize_t bytes;
341d4fb1e02SRoy Marples 	struct in_addr addr = astate->addr;
3427827cba2SAaron LI 
34380aa9461SRoy Marples 	if (events != ELE_READ)
34480aa9461SRoy Marples 		logerrx("%s: unexpected event 0x%04x", __func__, events);
34580aa9461SRoy Marples 
3467827cba2SAaron LI 	/* Some RAW mechanisms are generic file descriptors, not sockets.
3477827cba2SAaron LI 	 * This means we have no kernel call to just get one packet,
3487827cba2SAaron LI 	 * so we have to process the entire buffer. */
349d4fb1e02SRoy Marples 	bpf->bpf_flags &= ~BPF_EOF;
350d4fb1e02SRoy Marples 	while (!(bpf->bpf_flags & BPF_EOF)) {
351d4fb1e02SRoy Marples 		bytes = bpf_read(bpf, buf, sizeof(buf));
3527827cba2SAaron LI 		if (bytes == -1) {
3537827cba2SAaron LI 			logerr("%s: %s", __func__, ifp->name);
354d4fb1e02SRoy Marples 			arp_free(astate);
355d4fb1e02SRoy Marples 			return;
3567827cba2SAaron LI 		}
357d4fb1e02SRoy Marples 		arp_packet(ifp, buf, (size_t)bytes, bpf->bpf_flags);
3587827cba2SAaron LI 		/* Check we still have a state after processing. */
359d4fb1e02SRoy Marples 		if ((astate = arp_find(ifp, &addr)) == NULL)
360d4fb1e02SRoy Marples 			break;
361d4fb1e02SRoy Marples 		if ((bpf = astate->bpf) == NULL)
3627827cba2SAaron LI 			break;
3637827cba2SAaron LI 	}
3647827cba2SAaron LI }
3657827cba2SAaron LI 
3667827cba2SAaron LI static void
arp_probed(void * arg)3677827cba2SAaron LI arp_probed(void *arg)
3687827cba2SAaron LI {
3697827cba2SAaron LI 	struct arp_state *astate = arg;
3707827cba2SAaron LI 
3718d36e1dfSRoy Marples 	timespecclear(&astate->defend);
3728d36e1dfSRoy Marples 	astate->not_found_cb(astate);
3737827cba2SAaron LI }
3747827cba2SAaron LI 
3757827cba2SAaron LI static void
arp_probe1(void * arg)3767827cba2SAaron LI arp_probe1(void *arg)
3777827cba2SAaron LI {
3787827cba2SAaron LI 	struct arp_state *astate = arg;
3797827cba2SAaron LI 	struct interface *ifp = astate->iface;
3806e63cc1fSRoy Marples 	unsigned int delay;
3817827cba2SAaron LI 
3827827cba2SAaron LI 	if (++astate->probes < PROBE_NUM) {
3836e63cc1fSRoy Marples 		delay = (PROBE_MIN * MSEC_PER_SEC) +
3846e63cc1fSRoy Marples 		    (arc4random_uniform(
3856e63cc1fSRoy Marples 		    (PROBE_MAX - PROBE_MIN) * MSEC_PER_SEC));
3866e63cc1fSRoy Marples 		eloop_timeout_add_msec(ifp->ctx->eloop, delay, arp_probe1, astate);
3877827cba2SAaron LI 	} else {
3886e63cc1fSRoy Marples 		delay = ANNOUNCE_WAIT *	MSEC_PER_SEC;
3896e63cc1fSRoy Marples 		eloop_timeout_add_msec(ifp->ctx->eloop, delay, arp_probed, astate);
3907827cba2SAaron LI 	}
3917827cba2SAaron LI 	logdebugx("%s: ARP probing %s (%d of %d), next in %0.1f seconds",
3927827cba2SAaron LI 	    ifp->name, inet_ntoa(astate->addr),
3937827cba2SAaron LI 	    astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
3946e63cc1fSRoy Marples 	    (float)delay / MSEC_PER_SEC);
395d4fb1e02SRoy Marples 	if (arp_request(astate, NULL) == -1)
3967827cba2SAaron LI 		logerr(__func__);
3977827cba2SAaron LI }
3987827cba2SAaron LI 
3997827cba2SAaron LI void
arp_probe(struct arp_state * astate)4007827cba2SAaron LI arp_probe(struct arp_state *astate)
4017827cba2SAaron LI {
4027827cba2SAaron LI 
4037827cba2SAaron LI 	astate->probes = 0;
4047827cba2SAaron LI 	logdebugx("%s: probing for %s",
4057827cba2SAaron LI 	    astate->iface->name, inet_ntoa(astate->addr));
4067827cba2SAaron LI 	arp_probe1(astate);
4077827cba2SAaron LI }
4087827cba2SAaron LI #endif	/* ARP */
4097827cba2SAaron LI 
4106e63cc1fSRoy Marples struct arp_state *
arp_find(struct interface * ifp,const struct in_addr * addr)4118d36e1dfSRoy Marples arp_find(struct interface *ifp, const struct in_addr *addr)
4128d36e1dfSRoy Marples {
4138d36e1dfSRoy Marples 	struct iarp_state *state;
4148d36e1dfSRoy Marples 	struct arp_state *astate;
4158d36e1dfSRoy Marples 
4168d36e1dfSRoy Marples 	if ((state = ARP_STATE(ifp)) == NULL)
4178d36e1dfSRoy Marples 		goto out;
4188d36e1dfSRoy Marples 	TAILQ_FOREACH(astate, &state->arp_states, next) {
4198d36e1dfSRoy Marples 		if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
4208d36e1dfSRoy Marples 			return astate;
4218d36e1dfSRoy Marples 	}
4228d36e1dfSRoy Marples out:
4238d36e1dfSRoy Marples 	errno = ESRCH;
4248d36e1dfSRoy Marples 	return NULL;
4258d36e1dfSRoy Marples }
4268d36e1dfSRoy Marples 
4277827cba2SAaron LI static void
arp_announced(void * arg)4287827cba2SAaron LI arp_announced(void *arg)
4297827cba2SAaron LI {
4307827cba2SAaron LI 	struct arp_state *astate = arg;
4317827cba2SAaron LI 
4327827cba2SAaron LI 	if (astate->announced_cb) {
4337827cba2SAaron LI 		astate->announced_cb(astate);
4347827cba2SAaron LI 		return;
4357827cba2SAaron LI 	}
4367827cba2SAaron LI 
4377827cba2SAaron LI 	/* Keep the ARP state open to handle ongoing ACD. */
4387827cba2SAaron LI }
4397827cba2SAaron LI 
4407827cba2SAaron LI static void
arp_announce1(void * arg)4417827cba2SAaron LI arp_announce1(void *arg)
4427827cba2SAaron LI {
4437827cba2SAaron LI 	struct arp_state *astate = arg;
4447827cba2SAaron LI 	struct interface *ifp = astate->iface;
4451b3b16a2SRoy Marples 	struct ipv4_addr *ia;
4467827cba2SAaron LI 
4477827cba2SAaron LI 	if (++astate->claims < ANNOUNCE_NUM)
4487827cba2SAaron LI 		logdebugx("%s: ARP announcing %s (%d of %d), "
4497827cba2SAaron LI 		    "next in %d.0 seconds",
4507827cba2SAaron LI 		    ifp->name, inet_ntoa(astate->addr),
4517827cba2SAaron LI 		    astate->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
4527827cba2SAaron LI 	else
4537827cba2SAaron LI 		logdebugx("%s: ARP announcing %s (%d of %d)",
4547827cba2SAaron LI 		    ifp->name, inet_ntoa(astate->addr),
4557827cba2SAaron LI 		    astate->claims, ANNOUNCE_NUM);
4561b3b16a2SRoy Marples 
4571b3b16a2SRoy Marples 	/* The kernel will send a Gratuitous ARP for newly added addresses.
4581b3b16a2SRoy Marples 	 * So we can avoid sending the same.
4591b3b16a2SRoy Marples 	 * Linux is special and doesn't send one. */
4601b3b16a2SRoy Marples 	ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
4611b3b16a2SRoy Marples #ifndef __linux__
4621b3b16a2SRoy Marples 	if (astate->claims == 1 && ia != NULL && ia->flags & IPV4_AF_NEW)
4631b3b16a2SRoy Marples 		goto skip_request;
4641b3b16a2SRoy Marples #endif
4651b3b16a2SRoy Marples 
466d4fb1e02SRoy Marples 	if (arp_request(astate, &astate->addr) == -1)
4677827cba2SAaron LI 		logerr(__func__);
4681b3b16a2SRoy Marples 
4691b3b16a2SRoy Marples #ifndef __linux__
4701b3b16a2SRoy Marples skip_request:
4711b3b16a2SRoy Marples #endif
4721b3b16a2SRoy Marples 	/* No longer a new address. */
4731b3b16a2SRoy Marples 	if (ia != NULL)
4741b3b16a2SRoy Marples 		ia->flags |= ~IPV4_AF_NEW;
4751b3b16a2SRoy Marples 
4767827cba2SAaron LI 	eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
4777827cba2SAaron LI 	    astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
4787827cba2SAaron LI 	    astate);
4797827cba2SAaron LI }
4807827cba2SAaron LI 
481d4fb1e02SRoy Marples static void
arp_announce(struct arp_state * astate)4827827cba2SAaron LI arp_announce(struct arp_state *astate)
4837827cba2SAaron LI {
4847827cba2SAaron LI 	struct iarp_state *state;
4857827cba2SAaron LI 	struct interface *ifp;
4867827cba2SAaron LI 	struct arp_state *a2;
4877827cba2SAaron LI 	int r;
4887827cba2SAaron LI 
4897827cba2SAaron LI 	/* Cancel any other ARP announcements for this address. */
4907827cba2SAaron LI 	TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
4917827cba2SAaron LI 		state = ARP_STATE(ifp);
4927827cba2SAaron LI 		if (state == NULL)
4937827cba2SAaron LI 			continue;
4947827cba2SAaron LI 		TAILQ_FOREACH(a2, &state->arp_states, next) {
4957827cba2SAaron LI 			if (astate == a2 ||
4967827cba2SAaron LI 			    a2->addr.s_addr != astate->addr.s_addr)
4977827cba2SAaron LI 				continue;
4987827cba2SAaron LI 			r = eloop_timeout_delete(a2->iface->ctx->eloop,
4997827cba2SAaron LI 			    a2->claims < ANNOUNCE_NUM
5007827cba2SAaron LI 			    ? arp_announce1 : arp_announced,
5017827cba2SAaron LI 			    a2);
5027827cba2SAaron LI 			if (r == -1)
5037827cba2SAaron LI 				logerr(__func__);
504acd7a309SRoy Marples 			else if (r != 0) {
5057827cba2SAaron LI 				logdebugx("%s: ARP announcement "
5067827cba2SAaron LI 				    "of %s cancelled",
5077827cba2SAaron LI 				    a2->iface->name,
5087827cba2SAaron LI 				    inet_ntoa(a2->addr));
509acd7a309SRoy Marples 				arp_announced(a2);
510acd7a309SRoy Marples 			}
5117827cba2SAaron LI 		}
5127827cba2SAaron LI 	}
5137827cba2SAaron LI 
5147827cba2SAaron LI 	astate->claims = 0;
5157827cba2SAaron LI 	arp_announce1(astate);
5167827cba2SAaron LI }
5177827cba2SAaron LI 
518d4fb1e02SRoy Marples struct arp_state *
arp_ifannounceaddr(struct interface * ifp,const struct in_addr * ia)5198d36e1dfSRoy Marples arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
5207827cba2SAaron LI {
5217827cba2SAaron LI 	struct arp_state *astate;
5227827cba2SAaron LI 
523d4fb1e02SRoy Marples 	if (ifp->flags & IFF_NOARP || !(ifp->options->options & DHCPCD_ARP))
524d4fb1e02SRoy Marples 		return NULL;
5251b3b16a2SRoy Marples 
5267827cba2SAaron LI 	astate = arp_find(ifp, ia);
5278d36e1dfSRoy Marples 	if (astate == NULL) {
5287827cba2SAaron LI 		astate = arp_new(ifp, ia);
5298d36e1dfSRoy Marples 		if (astate == NULL)
530d4fb1e02SRoy Marples 			return NULL;
5318d36e1dfSRoy Marples 		astate->announced_cb = arp_free;
5328d36e1dfSRoy Marples 	}
5337827cba2SAaron LI 	arp_announce(astate);
534d4fb1e02SRoy Marples 	return astate;
5357827cba2SAaron LI }
5367827cba2SAaron LI 
537d4fb1e02SRoy Marples struct arp_state *
arp_announceaddr(struct dhcpcd_ctx * ctx,const struct in_addr * ia)5388d36e1dfSRoy Marples arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
5397827cba2SAaron LI {
5408d36e1dfSRoy Marples 	struct interface *ifp, *iff = NULL;
5418d36e1dfSRoy Marples 	struct ipv4_addr *iap;
5427827cba2SAaron LI 
5438d36e1dfSRoy Marples 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
54493ddca5eSRoy Marples 		if (!ifp->active || !if_is_link_up(ifp))
5458d36e1dfSRoy Marples 			continue;
5468d36e1dfSRoy Marples 		iap = ipv4_iffindaddr(ifp, ia, NULL);
5478d36e1dfSRoy Marples 		if (iap == NULL)
5488d36e1dfSRoy Marples 			continue;
5498d36e1dfSRoy Marples #ifdef IN_IFF_NOTUSEABLE
550d4fb1e02SRoy Marples 		if (iap->addr_flags & IN_IFF_NOTUSEABLE)
5518d36e1dfSRoy Marples 			continue;
5528d36e1dfSRoy Marples #endif
5538d36e1dfSRoy Marples 		if (iff != NULL && iff->metric < ifp->metric)
5548d36e1dfSRoy Marples 			continue;
5558d36e1dfSRoy Marples 		iff = ifp;
5567827cba2SAaron LI 	}
5578d36e1dfSRoy Marples 	if (iff == NULL)
558d4fb1e02SRoy Marples 		return NULL;
5597827cba2SAaron LI 
560d4fb1e02SRoy Marples 	return arp_ifannounceaddr(iff, ia);
5616e63cc1fSRoy Marples }
5626e63cc1fSRoy Marples 
5637827cba2SAaron LI struct arp_state *
arp_new(struct interface * ifp,const struct in_addr * addr)5647827cba2SAaron LI arp_new(struct interface *ifp, const struct in_addr *addr)
5657827cba2SAaron LI {
5667827cba2SAaron LI 	struct iarp_state *state;
5677827cba2SAaron LI 	struct arp_state *astate;
5687827cba2SAaron LI 
5697827cba2SAaron LI 	if ((state = ARP_STATE(ifp)) == NULL) {
5707827cba2SAaron LI 		ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state));
5717827cba2SAaron LI 		state = ARP_STATE(ifp);
5727827cba2SAaron LI 		if (state == NULL) {
5737827cba2SAaron LI 			logerr(__func__);
5747827cba2SAaron LI 			return NULL;
5757827cba2SAaron LI 		}
5767827cba2SAaron LI 		TAILQ_INIT(&state->arp_states);
5777827cba2SAaron LI 	} else {
578d4fb1e02SRoy Marples 		if ((astate = arp_find(ifp, addr)) != NULL)
5797827cba2SAaron LI 			return astate;
5807827cba2SAaron LI 	}
5817827cba2SAaron LI 
5827827cba2SAaron LI 	if ((astate = calloc(1, sizeof(*astate))) == NULL) {
5837827cba2SAaron LI 		logerr(__func__);
5847827cba2SAaron LI 		return NULL;
5857827cba2SAaron LI 	}
5867827cba2SAaron LI 	astate->iface = ifp;
587d4fb1e02SRoy Marples 	astate->addr = *addr;
588d4fb1e02SRoy Marples 
589d4fb1e02SRoy Marples #ifdef PRIVSEP
590d4fb1e02SRoy Marples 	if (IN_PRIVSEP(ifp->ctx)) {
591d4fb1e02SRoy Marples 		if (ps_bpf_openarp(ifp, addr) == -1) {
592d4fb1e02SRoy Marples 			logerr(__func__);
593d4fb1e02SRoy Marples 			free(astate);
594d4fb1e02SRoy Marples 			return NULL;
595d4fb1e02SRoy Marples 		}
596d4fb1e02SRoy Marples 	} else
597d4fb1e02SRoy Marples #endif
598d4fb1e02SRoy Marples 	{
599d4fb1e02SRoy Marples 		astate->bpf = bpf_open(ifp, bpf_arp, addr);
600d4fb1e02SRoy Marples 		if (astate->bpf == NULL) {
601d4fb1e02SRoy Marples 			logerr(__func__);
602d4fb1e02SRoy Marples 			free(astate);
603d4fb1e02SRoy Marples 			return NULL;
604d4fb1e02SRoy Marples 		}
60580aa9461SRoy Marples 		if (eloop_event_add(ifp->ctx->eloop, astate->bpf->bpf_fd, ELE_READ,
60680aa9461SRoy Marples 		    arp_read, astate) == -1)
60780aa9461SRoy Marples 			logerr("%s: eloop_event_add", __func__);
608d4fb1e02SRoy Marples 	}
609d4fb1e02SRoy Marples 
610d4fb1e02SRoy Marples 
6117827cba2SAaron LI 	state = ARP_STATE(ifp);
6127827cba2SAaron LI 	TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
6137827cba2SAaron LI 	return astate;
6147827cba2SAaron LI }
6157827cba2SAaron LI 
6167827cba2SAaron LI void
arp_free(struct arp_state * astate)6177827cba2SAaron LI arp_free(struct arp_state *astate)
6187827cba2SAaron LI {
6197827cba2SAaron LI 	struct interface *ifp;
620d4fb1e02SRoy Marples 	struct dhcpcd_ctx *ctx;
6217827cba2SAaron LI 	struct iarp_state *state;
6227827cba2SAaron LI 
6237827cba2SAaron LI 	if (astate == NULL)
6247827cba2SAaron LI 		return;
6257827cba2SAaron LI 
6267827cba2SAaron LI 	ifp = astate->iface;
627d4fb1e02SRoy Marples 	ctx = ifp->ctx;
628d4fb1e02SRoy Marples 	eloop_timeout_delete(ctx->eloop, NULL, astate);
629d4fb1e02SRoy Marples 
6307827cba2SAaron LI 	state =	ARP_STATE(ifp);
6317827cba2SAaron LI 	TAILQ_REMOVE(&state->arp_states, astate, next);
6327827cba2SAaron LI 	if (astate->free_cb)
6337827cba2SAaron LI 		astate->free_cb(astate);
634d4fb1e02SRoy Marples 
635d4fb1e02SRoy Marples #ifdef PRIVSEP
636d4fb1e02SRoy Marples 	if (IN_PRIVSEP(ctx) && ps_bpf_closearp(ifp, &astate->addr) == -1)
637d4fb1e02SRoy Marples 		logerr(__func__);
638d4fb1e02SRoy Marples #endif
639d4fb1e02SRoy Marples 	if (astate->bpf != NULL) {
640d4fb1e02SRoy Marples 		eloop_event_delete(ctx->eloop, astate->bpf->bpf_fd);
641d4fb1e02SRoy Marples 		bpf_close(astate->bpf);
642d4fb1e02SRoy Marples 	}
643d4fb1e02SRoy Marples 
6447827cba2SAaron LI 	free(astate);
645d4fb1e02SRoy Marples 
646d4fb1e02SRoy Marples 	if (TAILQ_FIRST(&state->arp_states) == NULL) {
647d4fb1e02SRoy Marples 		free(state);
648d4fb1e02SRoy Marples 		ifp->if_data[IF_DATA_ARP] = NULL;
649d4fb1e02SRoy Marples 	}
6507827cba2SAaron LI }
6517827cba2SAaron LI 
6527827cba2SAaron LI void
arp_freeaddr(struct interface * ifp,const struct in_addr * ia)6538d36e1dfSRoy Marples arp_freeaddr(struct interface *ifp, const struct in_addr *ia)
6547827cba2SAaron LI {
6558d36e1dfSRoy Marples 	struct arp_state *astate;
6567827cba2SAaron LI 
6578d36e1dfSRoy Marples 	astate = arp_find(ifp, ia);
6588d36e1dfSRoy Marples 	arp_free(astate);
6597827cba2SAaron LI }
6607827cba2SAaron LI 
6617827cba2SAaron LI void
arp_drop(struct interface * ifp)6627827cba2SAaron LI arp_drop(struct interface *ifp)
6637827cba2SAaron LI {
6647827cba2SAaron LI 	struct iarp_state *state;
6658d36e1dfSRoy Marples 	struct arp_state *astate;
6667827cba2SAaron LI 
6678d36e1dfSRoy Marples 	while ((state = ARP_STATE(ifp)) != NULL &&
6688d36e1dfSRoy Marples 	    (astate = TAILQ_FIRST(&state->arp_states)) != NULL)
6697827cba2SAaron LI 		arp_free(astate);
6707827cba2SAaron LI }
671