mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 20:51:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			139 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  */
 | |
| #include "lwip/opt.h"
 | |
| 
 | |
| /* don't build if not configured for use in lwipopts.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;
 | |
|     // Check that we're looking for ARP reply in ACD_PROBING state and DHCP_CHECKING state
 | |
|     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)));
 | |
|     /* did another host (not our mac addr) respond with the address we were offered by the DHCP server? */
 | |
|     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 {
 | |
|         // No conflict detected
 | |
|         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 /* LWIP_IPV4 && DHCP_DOES_ARP_CHECK */
 | 
