@@ -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
8283return  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 ){
8687esp_netif_t  *esp_netif = esp_netifs[interface];
8788esp_netif_dhcp_status_t  status = ESP_NETIF_DHCP_INIT;
8889esp_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" 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" 
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" 
162207 return  err;
163208 }
164- 
165209err = esp_netif_dhcps_start (esp_netif);
166210if (err){
167211 log_e (" DHCPS Start Failed! 0x%04x" 
0 commit comments