@@ -48,6 +48,7 @@ extern "C" {
4848#include < vector>
4949#include " sdkconfig.h"
5050
51+ #define _byte_swap32 (num ) (((num>>24 )&0xff ) | ((num<<8 )&0xff0000 ) | ((num>>8 )&0xff00 ) | ((num<<24 )&0xff000000 ))
5152ESP_EVENT_DEFINE_BASE (ARDUINO_EVENTS);
5253/*
5354 * Private (exposable) methods
@@ -82,7 +83,7 @@ esp_err_t set_esp_interface_hostname(esp_interface_t interface, const char * hos
8283 return ESP_FAIL;
8384}
8485
85- esp_err_t set_esp_interface_ip (esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress()){
86+ esp_err_t set_esp_interface_ip (esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress(), IPAddress dhcp_lease_start=INADDR_NONE ){
8687 esp_netif_t *esp_netif = esp_netifs[interface];
8788 esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
8889 esp_netif_ip_info_t info;
@@ -138,20 +139,64 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
138139
139140 dhcps_lease_t lease;
140141 lease.enable = true ;
141- uint32_t dhcp_ipaddr = static_cast <uint32_t >(local_ip);
142- // prevents DHCP lease range to overflow subnet/24 range
143- // there will be 11 addresses for DHCP to lease
144- uint8_t leaseStart = (uint8_t )(~subnet[3 ] - 12 );
145- if ((local_ip[3 ]) < leaseStart) {
146- lease.start_ip .addr = dhcp_ipaddr + (1 << 24 );
147- lease.end_ip .addr = dhcp_ipaddr + (11 << 24 );
148- } else {
149- // make range stay in the begining of the netmask range
150- dhcp_ipaddr = (dhcp_ipaddr & 0x00FFFFFF );
151- lease.start_ip .addr = dhcp_ipaddr + (1 << 24 );
152- lease.end_ip .addr = dhcp_ipaddr + (11 << 24 );
142+ uint8_t CIDR = WiFiGenericClass::calculateSubnetCIDR (subnet);
143+ log_v (" SoftAP: %s | Gateway: %s | DHCP Start: %s | Netmask: %s" , local_ip.toString ().c_str (), gateway.toString ().c_str (), dhcp_lease_start.toString ().c_str (), subnet.toString ().c_str ());
144+ // netmask must have room for at least 12 IP addresses (AP + GW + 10 DHCP Leasing addresses)
145+ // netmask also must be limited to the last 8 bits of IPv4, otherwise this function won't work
146+ // IDF NETIF checks netmask for the 3rd byte: https://github.com/espressif/esp-idf/blob/master/components/esp_netif/lwip/esp_netif_lwip.c#L1857-L1862
147+ if (CIDR > 28 || CIDR < 24 ) {
148+ log_e (" Bad netmask. It must be from /24 to /28 (255.255.255. 0<->240)" );
149+ return ESP_FAIL; // ESP_FAIL if initializing failed
150+ }
151+ // The code below is ready for any netmask, not limited to 255.255.255.0
152+ uint32_t netmask = _byte_swap32 (info.netmask .addr );
153+ uint32_t ap_ipaddr = _byte_swap32 (info.ip .addr );
154+ uint32_t dhcp_ipaddr = _byte_swap32 (static_cast <uint32_t >(dhcp_lease_start));
155+ dhcp_ipaddr = dhcp_ipaddr == 0 ? ap_ipaddr + 1 : dhcp_ipaddr;
156+ uint32_t leaseStartMax = ~netmask - 10 ;
157+ // there will be 10 addresses for DHCP to lease
158+ lease.start_ip .addr = dhcp_ipaddr;
159+ lease.end_ip .addr = lease.start_ip .addr + 10 ;
160+ // Check if local_ip is in the same subnet as the dhcp leasing range initial address
161+ if ((ap_ipaddr & netmask) != (dhcp_ipaddr & netmask)) {
162+ log_e (" The AP IP address (%s) and the DHCP start address (%s) must be in the same subnet" ,
163+ local_ip.toString ().c_str (), IPAddress (_byte_swap32 (dhcp_ipaddr)).toString ().c_str ());
164+ return ESP_FAIL; // ESP_FAIL if initializing failed
165+ }
166+ // prevents DHCP lease range to overflow subnet range
167+ if ((dhcp_ipaddr & ~netmask) >= leaseStartMax) {
168+ // make first DHCP lease addr stay in the begining of the netmask range
169+ lease.start_ip .addr = (dhcp_ipaddr & netmask) + 1 ;
170+ lease.end_ip .addr = lease.start_ip .addr + 10 ;
171+ log_w (" DHCP Lease out of range - Changing DHCP leasing start to %s" , IPAddress (_byte_swap32 (lease.start_ip .addr )).toString ().c_str ());
153172 }
173+ // Check if local_ip is within DHCP range
174+ if (ap_ipaddr >= lease.start_ip .addr && ap_ipaddr <= lease.end_ip .addr ) {
175+ log_e (" The AP IP address (%s) can't be within the DHCP range (%s -- %s)" ,
176+ local_ip.toString ().c_str (), IPAddress (_byte_swap32 (lease.start_ip .addr )).toString ().c_str (), IPAddress (_byte_swap32 (lease.end_ip .addr )).toString ().c_str ());
177+ return ESP_FAIL; // ESP_FAIL if initializing failed
178+ }
179+ // Check if gateway is within DHCP range
180+ uint32_t gw_ipaddr = _byte_swap32 (info.gw .addr );
181+ bool gw_in_same_subnet = (gw_ipaddr & netmask) == (ap_ipaddr & netmask);
182+ if (gw_in_same_subnet && gw_ipaddr >= lease.start_ip .addr && gw_ipaddr <= lease.end_ip .addr ) {
183+ log_e (" The GatewayP address (%s) can't be within the DHCP range (%s -- %s)" ,
184+ gateway.toString ().c_str (), IPAddress (_byte_swap32 (lease.start_ip .addr )).toString ().c_str (), IPAddress (_byte_swap32 (lease.end_ip .addr )).toString ().c_str ());
185+ return ESP_FAIL; // ESP_FAIL if initializing failed
186+ }
187+ // all done, just revert back byte order of DHCP lease range
188+ lease.start_ip .addr = _byte_swap32 (lease.start_ip .addr );
189+ lease.end_ip .addr = _byte_swap32 (lease.end_ip .addr );
154190 log_v (" DHCP Server Range: %s to %s" , IPAddress (lease.start_ip .addr ).toString ().c_str (), IPAddress (lease.end_ip .addr ).toString ().c_str ());
191+ err = tcpip_adapter_dhcps_option (
192+ (tcpip_adapter_dhcp_option_mode_t )TCPIP_ADAPTER_OP_SET,
193+ (tcpip_adapter_dhcp_option_id_t )ESP_NETIF_SUBNET_MASK,
194+ (void *)&info.netmask .addr , sizeof (info.netmask .addr )
195+ );
196+ if (err){
197+ log_e (" DHCPS Set Netmask Failed! 0x%04x" , err);
198+ return err;
199+ }
155200 err = tcpip_adapter_dhcps_option (
156201 (tcpip_adapter_dhcp_option_mode_t )TCPIP_ADAPTER_OP_SET,
157202 (tcpip_adapter_dhcp_option_id_t )REQUESTED_IP_ADDRESS,
@@ -161,7 +206,6 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
161206 log_e (" DHCPS Set Lease Failed! 0x%04x" , err);
162207 return err;
163208 }
164-
165209 err = esp_netif_dhcps_start (esp_netif);
166210 if (err){
167211 log_e (" DHCPS Start Failed! 0x%04x" , err);
0 commit comments