1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
33
34
35
40
41
42
43
47
48
49
53
54
55
56
57
58
59
60
61
64
65
66
67
70
71
72
73
74
75
76
81
82
83
84
85
90
91
104
105
106
107
108
109
110
111
114
115
118
119
125
126
127
128
137
138
/* ... */
#include "lwip/opt.h"
#if LWIP_IPV4 && DHCP_DOES_ARP_CHECK
#include "lwip/acd.h"
#include "lwip/dhcp.h"
#include "lwip/prot/dhcp.h"
#include "lwip/timeouts.h"
#define ACD_DHCP_ARP_REPLY_TIMEOUT_MS 500
static void
acd_dhcp_check_timeout_cb(void *arg);
static void
acd_suspend(struct netif *netif)
{
struct dhcp *dhcp;
struct acd *acd;
if (netif == NULL || (dhcp = netif_dhcp_data(netif)) == NULL) {
return;
}{...}
acd = &dhcp->acd;
acd->state = ACD_STATE_OFF;
sys_untimeout(acd_dhcp_check_timeout_cb, (void *)netif);
}{ ... }
void
acd_remove(struct netif *netif, struct acd *acd)
{
acd_suspend(netif);
acd->acd_conflict_callback = NULL;
}{ ... }
void
acd_netif_ip_addr_changed(struct netif *netif, const ip_addr_t *old_addr,
const ip_addr_t *new_addr)
{
acd_suspend(netif);
}{ ... }
void
acd_network_changed_link_down(struct netif *netif)
{
acd_suspend(netif);
}{ ... }
void
acd_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
{
struct dhcp *dhcp;
ip4_addr_t sipaddr;
struct eth_addr netifaddr;
struct acd *acd;
if (netif == NULL || (dhcp = netif_dhcp_data(netif)) == NULL) {
return;
}{...}
acd = &dhcp->acd;
if (hdr->opcode != PP_HTONS(ARP_REPLY) || dhcp->state != DHCP_STATE_CHECKING ||
acd->state != ACD_STATE_PROBING || acd->acd_conflict_callback == NULL) {
return;
}{...}
SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN);
IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr);
LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n",
ip4_addr_get_u32(&sipaddr)));
if (ip4_addr_eq(&sipaddr, &dhcp->offered_ip_addr) &&
!eth_addr_eq(&netifaddr, &hdr->shwaddr)) {
LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("acd_arp_reply(): arp reply matched with offered address, declining\n"));
dhcp->acd.acd_conflict_callback(netif, ACD_DECLINE);
}{...}
}{ ... }
err_t
acd_add(struct netif *netif, struct acd *acd,
acd_conflict_callback_t acd_conflict_callback)
{
acd->acd_conflict_callback = acd_conflict_callback;
return ERR_OK;
}{ ... }
static void send_probe_once(struct netif *netif)
{
struct dhcp *dhcp = netif_dhcp_data(netif);
if (etharp_query(netif, &dhcp->offered_ip_addr, NULL) != ERR_OK) {
LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("acd_send_probe_once(): could not perform ARP query\n"));
return;
}{...}
if (dhcp->tries < 255) {
dhcp->tries++;
}{...}
LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_send_probe_once(): set request timeout %"U16_F" msecs\n", ACD_DHCP_ARP_REPLY_TIMEOUT_MS));
sys_timeout(ACD_DHCP_ARP_REPLY_TIMEOUT_MS, acd_dhcp_check_timeout_cb, (void *)netif);
}{ ... }
static void
acd_dhcp_check_timeout_cb(void *arg)
{
struct netif *netif = (struct netif *)arg;
struct dhcp *dhcp;
struct acd *acd;
if (netif == NULL || (dhcp = netif_dhcp_data(netif)) == NULL) {
return;
}{...}
acd = &dhcp->acd;
if (acd->state != ACD_STATE_PROBING || acd->acd_conflict_callback == NULL || dhcp->state != DHCP_STATE_CHECKING) {
return;
}{...}
LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_dhcp_check_timeout_cb(): CHECKING, ARP request timed out\n"));
if (dhcp->tries <= 1) {
send_probe_once(netif);
}{...} else {
dhcp->acd.acd_conflict_callback(netif, ACD_IP_OK);
}{...}
}{ ... }
err_t
acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr)
{
if (netif == NULL || netif_dhcp_data(netif) == NULL) {
return ERR_ARG;
}{...}
acd->state = ACD_STATE_PROBING;
send_probe_once(netif);
return ERR_OK;
}{ ... }
/* ... */#endif