|
5 | 5 | #include "lwip/ip_addr.h"
|
6 | 6 | #include "lwip/err.h"
|
7 | 7 | #include "lwip/netif.h"
|
| 8 | +#include "dhcpserver/dhcpserver.h" |
| 9 | +#include "dhcpserver/dhcpserver_options.h" |
8 | 10 | #include "esp32-hal-log.h"
|
9 | 11 |
|
10 | 12 | static ESP_Network_Interface * _interfaces[ESP_NETIF_ID_MAX] = { NULL, NULL, NULL, NULL, NULL, NULL};
|
@@ -137,6 +139,7 @@ ESP_Network_Interface::ESP_Network_Interface()
|
137 | 139 | , _got_ip_event_id(-1)
|
138 | 140 | , _lost_ip_event_id(-1)
|
139 | 141 | , _interface_id(ESP_NETIF_ID_MAX)
|
| 142 | + , _is_server_if(false) |
140 | 143 | {}
|
141 | 144 |
|
142 | 145 | ESP_Network_Interface::~ESP_Network_Interface(){
|
@@ -238,10 +241,11 @@ void ESP_Network_Interface::destroyNetif() {
|
238 | 241 | }
|
239 | 242 | }
|
240 | 243 |
|
241 |
| -bool ESP_Network_Interface::initNetif(ESP_Network_Interface_ID interface_id) { |
| 244 | +bool ESP_Network_Interface::initNetif(ESP_Network_Interface_ID interface_id, bool server_interface) { |
242 | 245 | if(_esp_netif == NULL || interface_id >= ESP_NETIF_ID_MAX){
|
243 | 246 | return false;
|
244 | 247 | }
|
| 248 | + _is_server_if = server_interface; |
245 | 249 | _interface_id = interface_id;
|
246 | 250 | _got_ip_event_id = esp_netif_get_event_id(_esp_netif, ESP_NETIF_IP_EVENT_GOT_IP);
|
247 | 251 | _lost_ip_event_id = esp_netif_get_event_id(_esp_netif, ESP_NETIF_IP_EVENT_LOST_IP);
|
@@ -293,6 +297,29 @@ bool ESP_Network_Interface::enableIPv6(bool en)
|
293 | 297 | return true;
|
294 | 298 | }
|
295 | 299 |
|
| 300 | +bool ESP_Network_Interface::dnsIP(uint8_t dns_no, IPAddress ip) |
| 301 | +{ |
| 302 | + if(_esp_netif == NULL || dns_no > 2){ |
| 303 | + return false; |
| 304 | + } |
| 305 | + if(_is_server_if && dns_no > 0){ |
| 306 | + log_e("Server interfaces can have only one DNS server."); |
| 307 | + return false; |
| 308 | + } |
| 309 | + esp_netif_dns_info_t d; |
| 310 | + // ToDo: can this work with IPv6 addresses? |
| 311 | + d.ip.type = IPADDR_TYPE_V4; |
| 312 | + if(static_cast<uint32_t>(ip) != 0){ |
| 313 | + d.ip.u_addr.ip4.addr = static_cast<uint32_t>(ip); |
| 314 | + } else { |
| 315 | + d.ip.u_addr.ip4.addr = 0; |
| 316 | + } |
| 317 | + if(esp_netif_set_dns_info(_esp_netif, (esp_netif_dns_type_t)dns_no, &d) != ESP_OK){ |
| 318 | + return false; |
| 319 | + } |
| 320 | + return true; |
| 321 | +} |
| 322 | + |
296 | 323 | bool ESP_Network_Interface::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2, IPAddress dns3)
|
297 | 324 | {
|
298 | 325 | if(_esp_netif == NULL){
|
@@ -323,36 +350,124 @@ bool ESP_Network_Interface::config(IPAddress local_ip, IPAddress gateway, IPAddr
|
323 | 350 | d3.ip.u_addr.ip4.addr = 0;
|
324 | 351 | }
|
325 | 352 |
|
326 |
| - // Stop DHCPC |
327 |
| - err = esp_netif_dhcpc_stop(_esp_netif); |
328 |
| - if(err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED){ |
329 |
| - log_e("DHCP could not be stopped! Error: %d", err); |
330 |
| - return false; |
331 |
| - } |
332 |
| - |
333 |
| - clearStatusBits(ESP_NETIF_HAS_IP_BIT); |
| 353 | + if(_is_server_if){ |
| 354 | + // Stop DHCPS |
| 355 | + err = esp_netif_dhcps_stop(_esp_netif); |
| 356 | + if(err && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED){ |
| 357 | + log_e("DHCPS Stop Failed! 0x%04x: %s", err, esp_err_to_name(err)); |
| 358 | + return false; |
| 359 | + } |
334 | 360 |
|
335 |
| - // Set IPv4, Netmask, Gateway |
336 |
| - err = esp_netif_set_ip_info(_esp_netif, &info); |
337 |
| - if(err != ERR_OK){ |
338 |
| - log_e("ETH IP could not be configured! Error: %d", err); |
339 |
| - return false; |
340 |
| - } |
341 |
| - |
342 |
| - // Set DNS Servers |
343 |
| - esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d1); |
344 |
| - esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_BACKUP, &d2); |
345 |
| - esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_FALLBACK, &d3); |
346 |
| - |
347 |
| - // Start DHCPC if static IP was set |
348 |
| - if(info.ip.addr == 0){ |
349 |
| - err = esp_netif_dhcpc_start(_esp_netif); |
350 |
| - if(err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED){ |
351 |
| - log_w("DHCP could not be started! Error: %d", err); |
| 361 | + // Set IPv4, Netmask, Gateway |
| 362 | + err = esp_netif_set_ip_info(_esp_netif, &info); |
| 363 | + if(err){ |
| 364 | + log_e("Netif Set IP Failed! 0x%04x: %s", err, esp_err_to_name(err)); |
| 365 | + return false; |
| 366 | + } |
| 367 | + |
| 368 | + // Set DNS Server |
| 369 | + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d1); |
| 370 | + |
| 371 | + dhcps_lease_t lease; |
| 372 | + lease.enable = true; |
| 373 | + uint8_t CIDR = calculateSubnetCIDR(subnet); |
| 374 | + log_v("SoftAP: %s | Gateway: %s | DHCP Start: %s | Netmask: %s", local_ip.toString().c_str(), gateway.toString().c_str(), dns2.toString().c_str(), subnet.toString().c_str()); |
| 375 | + // netmask must have room for at least 12 IP addresses (AP + GW + 10 DHCP Leasing addresses) |
| 376 | + // netmask also must be limited to the last 8 bits of IPv4, otherwise this function won't work |
| 377 | + // 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 |
| 378 | + if (CIDR > 28 || CIDR < 24) { |
| 379 | + log_e("Bad netmask. It must be from /24 to /28 (255.255.255. 0<->240)"); |
| 380 | + return false; // ESP_FAIL if initializing failed |
| 381 | + } |
| 382 | + #define _byte_swap32(num) (((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000)) |
| 383 | + // The code below is ready for any netmask, not limited to 255.255.255.0 |
| 384 | + uint32_t netmask = _byte_swap32(info.netmask.addr); |
| 385 | + uint32_t ap_ipaddr = _byte_swap32(info.ip.addr); |
| 386 | + uint32_t dhcp_ipaddr = _byte_swap32(static_cast<uint32_t>(dns2)); |
| 387 | + dhcp_ipaddr = dhcp_ipaddr == 0 ? ap_ipaddr + 1 : dhcp_ipaddr; |
| 388 | + uint32_t leaseStartMax = ~netmask - 10; |
| 389 | + // there will be 10 addresses for DHCP to lease |
| 390 | + lease.start_ip.addr = dhcp_ipaddr; |
| 391 | + lease.end_ip.addr = lease.start_ip.addr + 10; |
| 392 | + // Check if local_ip is in the same subnet as the dhcp leasing range initial address |
| 393 | + if ((ap_ipaddr & netmask) != (dhcp_ipaddr & netmask)) { |
| 394 | + log_e("The AP IP address (%s) and the DHCP start address (%s) must be in the same subnet", |
| 395 | + local_ip.toString().c_str(), IPAddress(_byte_swap32(dhcp_ipaddr)).toString().c_str()); |
| 396 | + return false; // ESP_FAIL if initializing failed |
| 397 | + } |
| 398 | + // prevents DHCP lease range to overflow subnet range |
| 399 | + if ((dhcp_ipaddr & ~netmask) >= leaseStartMax) { |
| 400 | + // make first DHCP lease addr stay in the begining of the netmask range |
| 401 | + lease.start_ip.addr = (dhcp_ipaddr & netmask) + 1; |
| 402 | + lease.end_ip.addr = lease.start_ip.addr + 10; |
| 403 | + log_w("DHCP Lease out of range - Changing DHCP leasing start to %s", IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str()); |
| 404 | + } |
| 405 | + // Check if local_ip is within DHCP range |
| 406 | + if (ap_ipaddr >= lease.start_ip.addr && ap_ipaddr <= lease.end_ip.addr) { |
| 407 | + log_e("The AP IP address (%s) can't be within the DHCP range (%s -- %s)", |
| 408 | + 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()); |
| 409 | + return false; // ESP_FAIL if initializing failed |
| 410 | + } |
| 411 | + // Check if gateway is within DHCP range |
| 412 | + uint32_t gw_ipaddr = _byte_swap32(info.gw.addr); |
| 413 | + bool gw_in_same_subnet = (gw_ipaddr & netmask) == (ap_ipaddr & netmask); |
| 414 | + if (gw_in_same_subnet && gw_ipaddr >= lease.start_ip.addr && gw_ipaddr <= lease.end_ip.addr) { |
| 415 | + log_e("The GatewayP address (%s) can't be within the DHCP range (%s -- %s)", |
| 416 | + gateway.toString().c_str(), IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str()); |
| 417 | + return false; // ESP_FAIL if initializing failed |
| 418 | + } |
| 419 | + // all done, just revert back byte order of DHCP lease range |
| 420 | + lease.start_ip.addr = _byte_swap32(lease.start_ip.addr); |
| 421 | + lease.end_ip.addr = _byte_swap32(lease.end_ip.addr); |
| 422 | + log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString().c_str(), IPAddress(lease.end_ip.addr).toString().c_str()); |
| 423 | + err = esp_netif_dhcps_option( |
| 424 | + _esp_netif, |
| 425 | + ESP_NETIF_OP_SET, |
| 426 | + ESP_NETIF_REQUESTED_IP_ADDRESS, |
| 427 | + (void*)&lease, sizeof(dhcps_lease_t) |
| 428 | + ); |
| 429 | + if(err){ |
| 430 | + log_e("DHCPS Set Lease Failed! 0x%04x: %s", err, esp_err_to_name(err)); |
| 431 | + return false; |
| 432 | + } |
| 433 | + // Start DHCPS |
| 434 | + err = esp_netif_dhcps_start(_esp_netif); |
| 435 | + if(err){ |
| 436 | + log_e("DHCPS Start Failed! 0x%04x: %s", err, esp_err_to_name(err)); |
352 | 437 | return false;
|
353 | 438 | }
|
354 | 439 | } else {
|
355 |
| - setStatusBits(ESP_NETIF_HAS_IP_BIT); |
| 440 | + // Stop DHCPC |
| 441 | + err = esp_netif_dhcpc_stop(_esp_netif); |
| 442 | + if(err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED){ |
| 443 | + log_e("DHCP could not be stopped! Error: 0x%04x: %s", err, esp_err_to_name(err)); |
| 444 | + return false; |
| 445 | + } |
| 446 | + |
| 447 | + clearStatusBits(ESP_NETIF_HAS_IP_BIT); |
| 448 | + |
| 449 | + // Set IPv4, Netmask, Gateway |
| 450 | + err = esp_netif_set_ip_info(_esp_netif, &info); |
| 451 | + if(err != ERR_OK){ |
| 452 | + log_e("ETH IP could not be configured! Error: 0x%04x: %s", err, esp_err_to_name(err)); |
| 453 | + return false; |
| 454 | + } |
| 455 | + |
| 456 | + // Set DNS Servers |
| 457 | + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d1); |
| 458 | + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_BACKUP, &d2); |
| 459 | + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_FALLBACK, &d3); |
| 460 | + |
| 461 | + // Start DHCPC if static IP was set |
| 462 | + if(info.ip.addr == 0){ |
| 463 | + err = esp_netif_dhcpc_start(_esp_netif); |
| 464 | + if(err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED){ |
| 465 | + log_w("DHCP could not be started! Error: 0x%04x: %s", err, esp_err_to_name(err)); |
| 466 | + return false; |
| 467 | + } |
| 468 | + } else { |
| 469 | + setStatusBits(ESP_NETIF_HAS_IP_BIT); |
| 470 | + } |
356 | 471 | }
|
357 | 472 |
|
358 | 473 | return true;
|
|
0 commit comments