xref: /minix3/external/bsd/dhcpcd/dist/arp.c (revision 9f20bfa6c4c442e2e798d91b11c2a5f8d6833a41)
1*9f20bfa6SDavid van Moolenbroek #include <sys/cdefs.h>
2*9f20bfa6SDavid van Moolenbroek  __RCSID("$NetBSD: arp.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
3*9f20bfa6SDavid van Moolenbroek 
4*9f20bfa6SDavid van Moolenbroek /*
5*9f20bfa6SDavid van Moolenbroek  * dhcpcd - DHCP client daemon
6*9f20bfa6SDavid van Moolenbroek  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7*9f20bfa6SDavid van Moolenbroek  * All rights reserved
8*9f20bfa6SDavid van Moolenbroek 
9*9f20bfa6SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*9f20bfa6SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*9f20bfa6SDavid van Moolenbroek  * are met:
12*9f20bfa6SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*9f20bfa6SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*9f20bfa6SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*9f20bfa6SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
16*9f20bfa6SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
17*9f20bfa6SDavid van Moolenbroek  *
18*9f20bfa6SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*9f20bfa6SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*9f20bfa6SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*9f20bfa6SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*9f20bfa6SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*9f20bfa6SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*9f20bfa6SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*9f20bfa6SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*9f20bfa6SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*9f20bfa6SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*9f20bfa6SDavid van Moolenbroek  * SUCH DAMAGE.
29*9f20bfa6SDavid van Moolenbroek  */
30*9f20bfa6SDavid van Moolenbroek 
31*9f20bfa6SDavid van Moolenbroek #include <sys/socket.h>
32*9f20bfa6SDavid van Moolenbroek #include <sys/types.h>
33*9f20bfa6SDavid van Moolenbroek 
34*9f20bfa6SDavid van Moolenbroek #include <arpa/inet.h>
35*9f20bfa6SDavid van Moolenbroek 
36*9f20bfa6SDavid van Moolenbroek #include <net/if.h>
37*9f20bfa6SDavid van Moolenbroek #include <netinet/in.h>
38*9f20bfa6SDavid van Moolenbroek #include <netinet/if_ether.h>
39*9f20bfa6SDavid van Moolenbroek 
40*9f20bfa6SDavid van Moolenbroek #include <errno.h>
41*9f20bfa6SDavid van Moolenbroek #include <signal.h>
42*9f20bfa6SDavid van Moolenbroek #include <stdlib.h>
43*9f20bfa6SDavid van Moolenbroek #include <string.h>
44*9f20bfa6SDavid van Moolenbroek #include <unistd.h>
45*9f20bfa6SDavid van Moolenbroek 
46*9f20bfa6SDavid van Moolenbroek #define ELOOP_QUEUE 5
47*9f20bfa6SDavid van Moolenbroek #include "config.h"
48*9f20bfa6SDavid van Moolenbroek #include "arp.h"
49*9f20bfa6SDavid van Moolenbroek #include "if.h"
50*9f20bfa6SDavid van Moolenbroek #include "ipv4.h"
51*9f20bfa6SDavid van Moolenbroek #include "common.h"
52*9f20bfa6SDavid van Moolenbroek #include "dhcpcd.h"
53*9f20bfa6SDavid van Moolenbroek #include "eloop.h"
54*9f20bfa6SDavid van Moolenbroek #include "if.h"
55*9f20bfa6SDavid van Moolenbroek #include "if-options.h"
56*9f20bfa6SDavid van Moolenbroek #include "ipv4ll.h"
57*9f20bfa6SDavid van Moolenbroek 
58*9f20bfa6SDavid van Moolenbroek #define ARP_LEN								      \
59*9f20bfa6SDavid van Moolenbroek 	(sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
60*9f20bfa6SDavid van Moolenbroek 
61*9f20bfa6SDavid van Moolenbroek static ssize_t
arp_request(const struct interface * ifp,in_addr_t sip,in_addr_t tip)62*9f20bfa6SDavid van Moolenbroek arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
63*9f20bfa6SDavid van Moolenbroek {
64*9f20bfa6SDavid van Moolenbroek 	uint8_t arp_buffer[ARP_LEN];
65*9f20bfa6SDavid van Moolenbroek 	struct arphdr ar;
66*9f20bfa6SDavid van Moolenbroek 	size_t len;
67*9f20bfa6SDavid van Moolenbroek 	uint8_t *p;
68*9f20bfa6SDavid van Moolenbroek 
69*9f20bfa6SDavid van Moolenbroek 	ar.ar_hrd = htons(ifp->family);
70*9f20bfa6SDavid van Moolenbroek 	ar.ar_pro = htons(ETHERTYPE_IP);
71*9f20bfa6SDavid van Moolenbroek 	ar.ar_hln = ifp->hwlen;
72*9f20bfa6SDavid van Moolenbroek 	ar.ar_pln = sizeof(sip);
73*9f20bfa6SDavid van Moolenbroek 	ar.ar_op = htons(ARPOP_REQUEST);
74*9f20bfa6SDavid van Moolenbroek 
75*9f20bfa6SDavid van Moolenbroek 	p = arp_buffer;
76*9f20bfa6SDavid van Moolenbroek 	len = 0;
77*9f20bfa6SDavid van Moolenbroek 
78*9f20bfa6SDavid van Moolenbroek #define CHECK(fun, b, l)						\
79*9f20bfa6SDavid van Moolenbroek 	do {								\
80*9f20bfa6SDavid van Moolenbroek 		if (len + (l) > sizeof(arp_buffer))			\
81*9f20bfa6SDavid van Moolenbroek 			goto eexit;					\
82*9f20bfa6SDavid van Moolenbroek 		fun(p, (b), (l));					\
83*9f20bfa6SDavid van Moolenbroek 		p += (l);						\
84*9f20bfa6SDavid van Moolenbroek 		len += (l);						\
85*9f20bfa6SDavid van Moolenbroek 	} while (/* CONSTCOND */ 0)
86*9f20bfa6SDavid van Moolenbroek #define APPEND(b, l)	CHECK(memcpy, b, l)
87*9f20bfa6SDavid van Moolenbroek #define ZERO(l)		CHECK(memset, 0, l)
88*9f20bfa6SDavid van Moolenbroek 
89*9f20bfa6SDavid van Moolenbroek 	APPEND(&ar, sizeof(ar));
90*9f20bfa6SDavid van Moolenbroek 	APPEND(ifp->hwaddr, ifp->hwlen);
91*9f20bfa6SDavid van Moolenbroek 	APPEND(&sip, sizeof(sip));
92*9f20bfa6SDavid van Moolenbroek 	ZERO(ifp->hwlen);
93*9f20bfa6SDavid van Moolenbroek 	APPEND(&tip, sizeof(tip));
94*9f20bfa6SDavid van Moolenbroek 	return if_sendrawpacket(ifp, ETHERTYPE_ARP, arp_buffer, len);
95*9f20bfa6SDavid van Moolenbroek 
96*9f20bfa6SDavid van Moolenbroek eexit:
97*9f20bfa6SDavid van Moolenbroek 	errno = ENOBUFS;
98*9f20bfa6SDavid van Moolenbroek 	return -1;
99*9f20bfa6SDavid van Moolenbroek }
100*9f20bfa6SDavid van Moolenbroek 
101*9f20bfa6SDavid van Moolenbroek void
arp_report_conflicted(const struct arp_state * astate,const struct arp_msg * amsg)102*9f20bfa6SDavid van Moolenbroek arp_report_conflicted(const struct arp_state *astate, const struct arp_msg *amsg)
103*9f20bfa6SDavid van Moolenbroek {
104*9f20bfa6SDavid van Moolenbroek 
105*9f20bfa6SDavid van Moolenbroek 	if (amsg != NULL) {
106*9f20bfa6SDavid van Moolenbroek 		char buf[HWADDR_LEN * 3];
107*9f20bfa6SDavid van Moolenbroek 
108*9f20bfa6SDavid van Moolenbroek 		logger(astate->iface->ctx, LOG_ERR,
109*9f20bfa6SDavid van Moolenbroek 		    "%s: hardware address %s claims %s",
110*9f20bfa6SDavid van Moolenbroek 		    astate->iface->name,
111*9f20bfa6SDavid van Moolenbroek 		    hwaddr_ntoa(amsg->sha, astate->iface->hwlen,
112*9f20bfa6SDavid van Moolenbroek 		    buf, sizeof(buf)),
113*9f20bfa6SDavid van Moolenbroek 		    inet_ntoa(astate->failed));
114*9f20bfa6SDavid van Moolenbroek 	} else
115*9f20bfa6SDavid van Moolenbroek 		logger(astate->iface->ctx, LOG_ERR,
116*9f20bfa6SDavid van Moolenbroek 		    "%s: DAD detected %s",
117*9f20bfa6SDavid van Moolenbroek 		    astate->iface->name, inet_ntoa(astate->failed));
118*9f20bfa6SDavid van Moolenbroek }
119*9f20bfa6SDavid van Moolenbroek 
120*9f20bfa6SDavid van Moolenbroek static void
arp_packet(void * arg)121*9f20bfa6SDavid van Moolenbroek arp_packet(void *arg)
122*9f20bfa6SDavid van Moolenbroek {
123*9f20bfa6SDavid van Moolenbroek 	struct interface *ifp = arg;
124*9f20bfa6SDavid van Moolenbroek 	const struct interface *ifn;
125*9f20bfa6SDavid van Moolenbroek 	uint8_t arp_buffer[ARP_LEN];
126*9f20bfa6SDavid van Moolenbroek 	struct arphdr ar;
127*9f20bfa6SDavid van Moolenbroek 	struct arp_msg arm;
128*9f20bfa6SDavid van Moolenbroek 	ssize_t bytes;
129*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
130*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate, *astaten;
131*9f20bfa6SDavid van Moolenbroek 	unsigned char *hw_s, *hw_t;
132*9f20bfa6SDavid van Moolenbroek 	int flags;
133*9f20bfa6SDavid van Moolenbroek 
134*9f20bfa6SDavid van Moolenbroek 	state = ARP_STATE(ifp);
135*9f20bfa6SDavid van Moolenbroek 	flags = 0;
136*9f20bfa6SDavid van Moolenbroek 	while (!(flags & RAW_EOF)) {
137*9f20bfa6SDavid van Moolenbroek 		bytes = if_readrawpacket(ifp, ETHERTYPE_ARP,
138*9f20bfa6SDavid van Moolenbroek 		    arp_buffer, sizeof(arp_buffer), &flags);
139*9f20bfa6SDavid van Moolenbroek 		if (bytes == -1) {
140*9f20bfa6SDavid van Moolenbroek 			logger(ifp->ctx, LOG_ERR,
141*9f20bfa6SDavid van Moolenbroek 			    "%s: arp if_readrawpacket: %m", ifp->name);
142*9f20bfa6SDavid van Moolenbroek 			arp_close(ifp);
143*9f20bfa6SDavid van Moolenbroek 			return;
144*9f20bfa6SDavid van Moolenbroek 		}
145*9f20bfa6SDavid van Moolenbroek 		/* We must have a full ARP header */
146*9f20bfa6SDavid van Moolenbroek 		if ((size_t)bytes < sizeof(ar))
147*9f20bfa6SDavid van Moolenbroek 			continue;
148*9f20bfa6SDavid van Moolenbroek 		memcpy(&ar, arp_buffer, sizeof(ar));
149*9f20bfa6SDavid van Moolenbroek 		/* Families must match */
150*9f20bfa6SDavid van Moolenbroek 		if (ar.ar_hrd != htons(ifp->family))
151*9f20bfa6SDavid van Moolenbroek 			continue;
152*9f20bfa6SDavid van Moolenbroek 		/* Protocol must be IP. */
153*9f20bfa6SDavid van Moolenbroek 		if (ar.ar_pro != htons(ETHERTYPE_IP))
154*9f20bfa6SDavid van Moolenbroek 			continue;
155*9f20bfa6SDavid van Moolenbroek 		if (ar.ar_pln != sizeof(arm.sip.s_addr))
156*9f20bfa6SDavid van Moolenbroek 			continue;
157*9f20bfa6SDavid van Moolenbroek 		/* Only these types are recognised */
158*9f20bfa6SDavid van Moolenbroek 		if (ar.ar_op != htons(ARPOP_REPLY) &&
159*9f20bfa6SDavid van Moolenbroek 		    ar.ar_op != htons(ARPOP_REQUEST))
160*9f20bfa6SDavid van Moolenbroek 			continue;
161*9f20bfa6SDavid van Moolenbroek 
162*9f20bfa6SDavid van Moolenbroek 		/* Get pointers to the hardware addreses */
163*9f20bfa6SDavid van Moolenbroek 		hw_s = arp_buffer + sizeof(ar);
164*9f20bfa6SDavid van Moolenbroek 		hw_t = hw_s + ar.ar_hln + ar.ar_pln;
165*9f20bfa6SDavid van Moolenbroek 		/* Ensure we got all the data */
166*9f20bfa6SDavid van Moolenbroek 		if ((hw_t + ar.ar_hln + ar.ar_pln) - arp_buffer > bytes)
167*9f20bfa6SDavid van Moolenbroek 			continue;
168*9f20bfa6SDavid van Moolenbroek 		/* Ignore messages from ourself */
169*9f20bfa6SDavid van Moolenbroek 		TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
170*9f20bfa6SDavid van Moolenbroek 			if (ar.ar_hln == ifn->hwlen &&
171*9f20bfa6SDavid van Moolenbroek 			    memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
172*9f20bfa6SDavid van Moolenbroek 				break;
173*9f20bfa6SDavid van Moolenbroek 		}
174*9f20bfa6SDavid van Moolenbroek 		if (ifn)
175*9f20bfa6SDavid van Moolenbroek 			continue;
176*9f20bfa6SDavid van Moolenbroek 		/* Copy out the HW and IP addresses */
177*9f20bfa6SDavid van Moolenbroek 		memcpy(&arm.sha, hw_s, ar.ar_hln);
178*9f20bfa6SDavid van Moolenbroek 		memcpy(&arm.sip.s_addr, hw_s + ar.ar_hln, ar.ar_pln);
179*9f20bfa6SDavid van Moolenbroek 		memcpy(&arm.tha, hw_t, ar.ar_hln);
180*9f20bfa6SDavid van Moolenbroek 		memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
181*9f20bfa6SDavid van Moolenbroek 
182*9f20bfa6SDavid van Moolenbroek 		/* Run the conflicts */
183*9f20bfa6SDavid van Moolenbroek 		TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
184*9f20bfa6SDavid van Moolenbroek 			if (astate->conflicted_cb)
185*9f20bfa6SDavid van Moolenbroek 				astate->conflicted_cb(astate, &arm);
186*9f20bfa6SDavid van Moolenbroek 		}
187*9f20bfa6SDavid van Moolenbroek 	}
188*9f20bfa6SDavid van Moolenbroek }
189*9f20bfa6SDavid van Moolenbroek 
190*9f20bfa6SDavid van Moolenbroek static void
arp_open(struct interface * ifp)191*9f20bfa6SDavid van Moolenbroek arp_open(struct interface *ifp)
192*9f20bfa6SDavid van Moolenbroek {
193*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
194*9f20bfa6SDavid van Moolenbroek 
195*9f20bfa6SDavid van Moolenbroek 	state = ARP_STATE(ifp);
196*9f20bfa6SDavid van Moolenbroek 	if (state->fd == -1) {
197*9f20bfa6SDavid van Moolenbroek 		state->fd = if_openrawsocket(ifp, ETHERTYPE_ARP);
198*9f20bfa6SDavid van Moolenbroek 		if (state->fd == -1) {
199*9f20bfa6SDavid van Moolenbroek 			logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
200*9f20bfa6SDavid van Moolenbroek 			    __func__, ifp->name);
201*9f20bfa6SDavid van Moolenbroek 			return;
202*9f20bfa6SDavid van Moolenbroek 		}
203*9f20bfa6SDavid van Moolenbroek 		eloop_event_add(ifp->ctx->eloop, state->fd,
204*9f20bfa6SDavid van Moolenbroek 		    arp_packet, ifp, NULL, NULL);
205*9f20bfa6SDavid van Moolenbroek 	}
206*9f20bfa6SDavid van Moolenbroek }
207*9f20bfa6SDavid van Moolenbroek 
208*9f20bfa6SDavid van Moolenbroek static void
arp_announced(void * arg)209*9f20bfa6SDavid van Moolenbroek arp_announced(void *arg)
210*9f20bfa6SDavid van Moolenbroek {
211*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate = arg;
212*9f20bfa6SDavid van Moolenbroek 
213*9f20bfa6SDavid van Moolenbroek 	if (astate->announced_cb) {
214*9f20bfa6SDavid van Moolenbroek 		astate->announced_cb(astate);
215*9f20bfa6SDavid van Moolenbroek 		return;
216*9f20bfa6SDavid van Moolenbroek 	}
217*9f20bfa6SDavid van Moolenbroek 
218*9f20bfa6SDavid van Moolenbroek 	/* Nothing more to do, so free us */
219*9f20bfa6SDavid van Moolenbroek 	arp_free(astate);
220*9f20bfa6SDavid van Moolenbroek }
221*9f20bfa6SDavid van Moolenbroek 
222*9f20bfa6SDavid van Moolenbroek static void
arp_announce1(void * arg)223*9f20bfa6SDavid van Moolenbroek arp_announce1(void *arg)
224*9f20bfa6SDavid van Moolenbroek {
225*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate = arg;
226*9f20bfa6SDavid van Moolenbroek 	struct interface *ifp = astate->iface;
227*9f20bfa6SDavid van Moolenbroek 
228*9f20bfa6SDavid van Moolenbroek 	if (++astate->claims < ANNOUNCE_NUM)
229*9f20bfa6SDavid van Moolenbroek 		logger(ifp->ctx, LOG_DEBUG,
230*9f20bfa6SDavid van Moolenbroek 		    "%s: ARP announcing %s (%d of %d), "
231*9f20bfa6SDavid van Moolenbroek 		    "next in %d.0 seconds",
232*9f20bfa6SDavid van Moolenbroek 		    ifp->name, inet_ntoa(astate->addr),
233*9f20bfa6SDavid van Moolenbroek 		    astate->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
234*9f20bfa6SDavid van Moolenbroek 	else
235*9f20bfa6SDavid van Moolenbroek 		logger(ifp->ctx, LOG_DEBUG,
236*9f20bfa6SDavid van Moolenbroek 		    "%s: ARP announcing %s (%d of %d)",
237*9f20bfa6SDavid van Moolenbroek 		    ifp->name, inet_ntoa(astate->addr),
238*9f20bfa6SDavid van Moolenbroek 		    astate->claims, ANNOUNCE_NUM);
239*9f20bfa6SDavid van Moolenbroek 	if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr) == -1)
240*9f20bfa6SDavid van Moolenbroek 		logger(ifp->ctx, LOG_ERR, "send_arp: %m");
241*9f20bfa6SDavid van Moolenbroek 	eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
242*9f20bfa6SDavid van Moolenbroek 	    astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
243*9f20bfa6SDavid van Moolenbroek 	    astate);
244*9f20bfa6SDavid van Moolenbroek }
245*9f20bfa6SDavid van Moolenbroek 
246*9f20bfa6SDavid van Moolenbroek void
arp_announce(struct arp_state * astate)247*9f20bfa6SDavid van Moolenbroek arp_announce(struct arp_state *astate)
248*9f20bfa6SDavid van Moolenbroek {
249*9f20bfa6SDavid van Moolenbroek 
250*9f20bfa6SDavid van Moolenbroek 	arp_open(astate->iface);
251*9f20bfa6SDavid van Moolenbroek 	astate->claims = 0;
252*9f20bfa6SDavid van Moolenbroek 	arp_announce1(astate);
253*9f20bfa6SDavid van Moolenbroek }
254*9f20bfa6SDavid van Moolenbroek 
255*9f20bfa6SDavid van Moolenbroek static void
arp_probed(void * arg)256*9f20bfa6SDavid van Moolenbroek arp_probed(void *arg)
257*9f20bfa6SDavid van Moolenbroek {
258*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate = arg;
259*9f20bfa6SDavid van Moolenbroek 
260*9f20bfa6SDavid van Moolenbroek 	astate->probed_cb(astate);
261*9f20bfa6SDavid van Moolenbroek }
262*9f20bfa6SDavid van Moolenbroek 
263*9f20bfa6SDavid van Moolenbroek static void
arp_probe1(void * arg)264*9f20bfa6SDavid van Moolenbroek arp_probe1(void *arg)
265*9f20bfa6SDavid van Moolenbroek {
266*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate = arg;
267*9f20bfa6SDavid van Moolenbroek 	struct interface *ifp = astate->iface;
268*9f20bfa6SDavid van Moolenbroek 	struct timespec tv;
269*9f20bfa6SDavid van Moolenbroek 
270*9f20bfa6SDavid van Moolenbroek 	if (++astate->probes < PROBE_NUM) {
271*9f20bfa6SDavid van Moolenbroek 		tv.tv_sec = PROBE_MIN;
272*9f20bfa6SDavid van Moolenbroek 		tv.tv_nsec = (suseconds_t)arc4random_uniform(
273*9f20bfa6SDavid van Moolenbroek 		    (PROBE_MAX - PROBE_MIN) * NSEC_PER_SEC);
274*9f20bfa6SDavid van Moolenbroek 		timespecnorm(&tv);
275*9f20bfa6SDavid van Moolenbroek 		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probe1, astate);
276*9f20bfa6SDavid van Moolenbroek 	} else {
277*9f20bfa6SDavid van Moolenbroek 		tv.tv_sec = ANNOUNCE_WAIT;
278*9f20bfa6SDavid van Moolenbroek 		tv.tv_nsec = 0;
279*9f20bfa6SDavid van Moolenbroek 		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probed, astate);
280*9f20bfa6SDavid van Moolenbroek 	}
281*9f20bfa6SDavid van Moolenbroek 	logger(ifp->ctx, LOG_DEBUG,
282*9f20bfa6SDavid van Moolenbroek 	    "%s: ARP probing %s (%d of %d), next in %0.1f seconds",
283*9f20bfa6SDavid van Moolenbroek 	    ifp->name, inet_ntoa(astate->addr),
284*9f20bfa6SDavid van Moolenbroek 	    astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
285*9f20bfa6SDavid van Moolenbroek 	    timespec_to_double(&tv));
286*9f20bfa6SDavid van Moolenbroek 	if (arp_request(ifp, 0, astate->addr.s_addr) == -1)
287*9f20bfa6SDavid van Moolenbroek 		logger(ifp->ctx, LOG_ERR, "send_arp: %m");
288*9f20bfa6SDavid van Moolenbroek }
289*9f20bfa6SDavid van Moolenbroek 
290*9f20bfa6SDavid van Moolenbroek void
arp_probe(struct arp_state * astate)291*9f20bfa6SDavid van Moolenbroek arp_probe(struct arp_state *astate)
292*9f20bfa6SDavid van Moolenbroek {
293*9f20bfa6SDavid van Moolenbroek 
294*9f20bfa6SDavid van Moolenbroek 	arp_open(astate->iface);
295*9f20bfa6SDavid van Moolenbroek 	astate->probes = 0;
296*9f20bfa6SDavid van Moolenbroek 	logger(astate->iface->ctx, LOG_DEBUG, "%s: probing for %s",
297*9f20bfa6SDavid van Moolenbroek 	    astate->iface->name, inet_ntoa(astate->addr));
298*9f20bfa6SDavid van Moolenbroek 	arp_probe1(astate);
299*9f20bfa6SDavid van Moolenbroek }
300*9f20bfa6SDavid van Moolenbroek 
301*9f20bfa6SDavid van Moolenbroek struct arp_state *
arp_find(struct interface * ifp,const struct in_addr * addr)302*9f20bfa6SDavid van Moolenbroek arp_find(struct interface *ifp, const struct in_addr *addr)
303*9f20bfa6SDavid van Moolenbroek {
304*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
305*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate;
306*9f20bfa6SDavid van Moolenbroek 
307*9f20bfa6SDavid van Moolenbroek 	if ((state = ARP_STATE(ifp)) == NULL)
308*9f20bfa6SDavid van Moolenbroek 		goto out;
309*9f20bfa6SDavid van Moolenbroek 	TAILQ_FOREACH(astate, &state->arp_states, next) {
310*9f20bfa6SDavid van Moolenbroek 		if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
311*9f20bfa6SDavid van Moolenbroek 			return astate;
312*9f20bfa6SDavid van Moolenbroek 	}
313*9f20bfa6SDavid van Moolenbroek out:
314*9f20bfa6SDavid van Moolenbroek 	errno = ESRCH;
315*9f20bfa6SDavid van Moolenbroek 	return NULL;
316*9f20bfa6SDavid van Moolenbroek }
317*9f20bfa6SDavid van Moolenbroek 
318*9f20bfa6SDavid van Moolenbroek struct arp_state *
arp_new(struct interface * ifp,const struct in_addr * addr)319*9f20bfa6SDavid van Moolenbroek arp_new(struct interface *ifp, const struct in_addr *addr)
320*9f20bfa6SDavid van Moolenbroek {
321*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
322*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate;
323*9f20bfa6SDavid van Moolenbroek 
324*9f20bfa6SDavid van Moolenbroek 	if ((state = ARP_STATE(ifp)) == NULL) {
325*9f20bfa6SDavid van Moolenbroek 	        ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state));
326*9f20bfa6SDavid van Moolenbroek 		state = ARP_STATE(ifp);
327*9f20bfa6SDavid van Moolenbroek 		if (state == NULL) {
328*9f20bfa6SDavid van Moolenbroek 			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
329*9f20bfa6SDavid van Moolenbroek 			return NULL;
330*9f20bfa6SDavid van Moolenbroek 		}
331*9f20bfa6SDavid van Moolenbroek 		state->fd = -1;
332*9f20bfa6SDavid van Moolenbroek 		TAILQ_INIT(&state->arp_states);
333*9f20bfa6SDavid van Moolenbroek 	} else {
334*9f20bfa6SDavid van Moolenbroek 		if (addr && (astate = arp_find(ifp, addr)))
335*9f20bfa6SDavid van Moolenbroek 			return astate;
336*9f20bfa6SDavid van Moolenbroek 	}
337*9f20bfa6SDavid van Moolenbroek 
338*9f20bfa6SDavid van Moolenbroek 	if ((astate = calloc(1, sizeof(*astate))) == NULL) {
339*9f20bfa6SDavid van Moolenbroek 		logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
340*9f20bfa6SDavid van Moolenbroek 		return NULL;
341*9f20bfa6SDavid van Moolenbroek 	}
342*9f20bfa6SDavid van Moolenbroek 	astate->iface = ifp;
343*9f20bfa6SDavid van Moolenbroek 	if (addr)
344*9f20bfa6SDavid van Moolenbroek 		astate->addr = *addr;
345*9f20bfa6SDavid van Moolenbroek 	state = ARP_STATE(ifp);
346*9f20bfa6SDavid van Moolenbroek 	TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
347*9f20bfa6SDavid van Moolenbroek 	return astate;
348*9f20bfa6SDavid van Moolenbroek }
349*9f20bfa6SDavid van Moolenbroek 
350*9f20bfa6SDavid van Moolenbroek void
arp_cancel(struct arp_state * astate)351*9f20bfa6SDavid van Moolenbroek arp_cancel(struct arp_state *astate)
352*9f20bfa6SDavid van Moolenbroek {
353*9f20bfa6SDavid van Moolenbroek 
354*9f20bfa6SDavid van Moolenbroek 	eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate);
355*9f20bfa6SDavid van Moolenbroek }
356*9f20bfa6SDavid van Moolenbroek 
357*9f20bfa6SDavid van Moolenbroek void
arp_free(struct arp_state * astate)358*9f20bfa6SDavid van Moolenbroek arp_free(struct arp_state *astate)
359*9f20bfa6SDavid van Moolenbroek {
360*9f20bfa6SDavid van Moolenbroek 
361*9f20bfa6SDavid van Moolenbroek 	if (astate != NULL) {
362*9f20bfa6SDavid van Moolenbroek 		struct interface *ifp;
363*9f20bfa6SDavid van Moolenbroek 		struct iarp_state *state;
364*9f20bfa6SDavid van Moolenbroek 
365*9f20bfa6SDavid van Moolenbroek 		ifp = astate->iface;
366*9f20bfa6SDavid van Moolenbroek 		eloop_timeout_delete(ifp->ctx->eloop, NULL, astate);
367*9f20bfa6SDavid van Moolenbroek 		state =	ARP_STATE(ifp);
368*9f20bfa6SDavid van Moolenbroek 		TAILQ_REMOVE(&state->arp_states, astate, next);
369*9f20bfa6SDavid van Moolenbroek 		if (astate->free_cb)
370*9f20bfa6SDavid van Moolenbroek 			astate->free_cb(astate);
371*9f20bfa6SDavid van Moolenbroek 		free(astate);
372*9f20bfa6SDavid van Moolenbroek 
373*9f20bfa6SDavid van Moolenbroek 		/* If there are no more ARP states, close the socket. */
374*9f20bfa6SDavid van Moolenbroek 		if (state->fd != -1 &&
375*9f20bfa6SDavid van Moolenbroek 		    TAILQ_FIRST(&state->arp_states) == NULL)
376*9f20bfa6SDavid van Moolenbroek 		{
377*9f20bfa6SDavid van Moolenbroek 			eloop_event_delete(ifp->ctx->eloop, state->fd);
378*9f20bfa6SDavid van Moolenbroek 			close(state->fd);
379*9f20bfa6SDavid van Moolenbroek 			free(state);
380*9f20bfa6SDavid van Moolenbroek 			ifp->if_data[IF_DATA_ARP] = NULL;
381*9f20bfa6SDavid van Moolenbroek 		}
382*9f20bfa6SDavid van Moolenbroek 	}
383*9f20bfa6SDavid van Moolenbroek }
384*9f20bfa6SDavid van Moolenbroek 
385*9f20bfa6SDavid van Moolenbroek void
arp_free_but(struct arp_state * astate)386*9f20bfa6SDavid van Moolenbroek arp_free_but(struct arp_state *astate)
387*9f20bfa6SDavid van Moolenbroek {
388*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
389*9f20bfa6SDavid van Moolenbroek 	struct arp_state *p, *n;
390*9f20bfa6SDavid van Moolenbroek 
391*9f20bfa6SDavid van Moolenbroek 	state = ARP_STATE(astate->iface);
392*9f20bfa6SDavid van Moolenbroek 	TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) {
393*9f20bfa6SDavid van Moolenbroek 		if (p != astate)
394*9f20bfa6SDavid van Moolenbroek 			arp_free(p);
395*9f20bfa6SDavid van Moolenbroek 	}
396*9f20bfa6SDavid van Moolenbroek }
397*9f20bfa6SDavid van Moolenbroek 
398*9f20bfa6SDavid van Moolenbroek void
arp_close(struct interface * ifp)399*9f20bfa6SDavid van Moolenbroek arp_close(struct interface *ifp)
400*9f20bfa6SDavid van Moolenbroek {
401*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
402*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate;
403*9f20bfa6SDavid van Moolenbroek 
404*9f20bfa6SDavid van Moolenbroek 	/* Freeing the last state will also free the main state,
405*9f20bfa6SDavid van Moolenbroek 	 * so test for both. */
406*9f20bfa6SDavid van Moolenbroek 	for (;;) {
407*9f20bfa6SDavid van Moolenbroek 		if ((state = ARP_STATE(ifp)) == NULL ||
408*9f20bfa6SDavid van Moolenbroek 		    (astate = TAILQ_FIRST(&state->arp_states)) == NULL)
409*9f20bfa6SDavid van Moolenbroek 			break;
410*9f20bfa6SDavid van Moolenbroek 		arp_free(astate);
411*9f20bfa6SDavid van Moolenbroek 	}
412*9f20bfa6SDavid van Moolenbroek }
413*9f20bfa6SDavid van Moolenbroek 
414*9f20bfa6SDavid van Moolenbroek void
arp_handleifa(int cmd,struct interface * ifp,const struct in_addr * addr,int flags)415*9f20bfa6SDavid van Moolenbroek arp_handleifa(int cmd, struct interface *ifp, const struct in_addr *addr,
416*9f20bfa6SDavid van Moolenbroek     int flags)
417*9f20bfa6SDavid van Moolenbroek {
418*9f20bfa6SDavid van Moolenbroek #ifdef IN_IFF_DUPLICATED
419*9f20bfa6SDavid van Moolenbroek 	struct iarp_state *state;
420*9f20bfa6SDavid van Moolenbroek 	struct arp_state *astate, *asn;
421*9f20bfa6SDavid van Moolenbroek 
422*9f20bfa6SDavid van Moolenbroek 	if (cmd != RTM_NEWADDR || (state = ARP_STATE(ifp)) == NULL)
423*9f20bfa6SDavid van Moolenbroek 		return;
424*9f20bfa6SDavid van Moolenbroek 
425*9f20bfa6SDavid van Moolenbroek 	TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) {
426*9f20bfa6SDavid van Moolenbroek 		if (astate->addr.s_addr == addr->s_addr) {
427*9f20bfa6SDavid van Moolenbroek 			if (flags & IN_IFF_DUPLICATED) {
428*9f20bfa6SDavid van Moolenbroek 				if (astate->conflicted_cb)
429*9f20bfa6SDavid van Moolenbroek 					astate->conflicted_cb(astate, NULL);
430*9f20bfa6SDavid van Moolenbroek 			} else if (!(flags & IN_IFF_NOTUSEABLE)) {
431*9f20bfa6SDavid van Moolenbroek 				if (astate->probed_cb)
432*9f20bfa6SDavid van Moolenbroek 					astate->probed_cb(astate);
433*9f20bfa6SDavid van Moolenbroek 			}
434*9f20bfa6SDavid van Moolenbroek 		}
435*9f20bfa6SDavid van Moolenbroek 	}
436*9f20bfa6SDavid van Moolenbroek #else
437*9f20bfa6SDavid van Moolenbroek 	UNUSED(cmd);
438*9f20bfa6SDavid van Moolenbroek 	UNUSED(ifp);
439*9f20bfa6SDavid van Moolenbroek 	UNUSED(addr);
440*9f20bfa6SDavid van Moolenbroek 	UNUSED(flags);
441*9f20bfa6SDavid van Moolenbroek #endif
442*9f20bfa6SDavid van Moolenbroek }
443