@@ -48,6 +48,7 @@ extern "C" {
48
48
#include < vector>
49
49
#include " sdkconfig.h"
50
50
51
+ #define _byte_swap32 (num ) (((num>>24 )&0xff ) | ((num<<8 )&0xff0000 ) | ((num>>8 )&0xff00 ) | ((num<<24 )&0xff000000 ))
51
52
ESP_EVENT_DEFINE_BASE (ARDUINO_EVENTS);
52
53
/*
53
54
* Private (exposable) methods
@@ -82,7 +83,7 @@ esp_err_t set_esp_interface_hostname(esp_interface_t interface, const char * hos
82
83
return ESP_FAIL;
83
84
}
84
85
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 ){
86
87
esp_netif_t *esp_netif = esp_netifs[interface];
87
88
esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
88
89
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
138
139
139
140
dhcps_lease_t lease;
140
141
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 ());
153
172
}
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 );
154
190
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
+ }
155
200
err = tcpip_adapter_dhcps_option (
156
201
(tcpip_adapter_dhcp_option_mode_t )TCPIP_ADAPTER_OP_SET,
157
202
(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
161
206
log_e (" DHCPS Set Lease Failed! 0x%04x" , err);
162
207
return err;
163
208
}
164
-
165
209
err = esp_netif_dhcps_start (esp_netif);
166
210
if (err){
167
211
log_e (" DHCPS Start Failed! 0x%04x" , err);
0 commit comments