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