2021-08-01 16:48:19 +01:00
|
|
|
/*
|
|
|
|
xdrv_58_range_extender.ino - WiFi Range Extender for Tasmota
|
|
|
|
|
|
|
|
Copyright (C) 2021 sillyfrog and Theo Arends
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER
|
|
|
|
/*********************************************************************************************
|
|
|
|
To use this, add the following to your user_config_override.h
|
|
|
|
#define USE_WIFI_RANGE_EXTENDER
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
Additionally, for the ESP8266, PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH must be
|
|
|
|
set in your build options.
|
2021-08-01 16:48:19 +01:00
|
|
|
For example, in your platfromio_tasmota_cenv.ini, you will need an entry such as:
|
|
|
|
[env:tasmota-rangeextender]
|
|
|
|
build_flags = ${common.build_flags}
|
|
|
|
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
For the ESP32, the arduino-esp32 library must be at least version 2, with
|
|
|
|
CONFIG_LWIP_IP_FORWARD option set, and optionally CONFIG_LWIP_IPV4_NAPT.
|
|
|
|
|
2021-08-01 16:48:19 +01:00
|
|
|
If you want to support NAPT (removing the need for routes on a core router):
|
|
|
|
#define USE_WIFI_RANGE_EXTENDER_NAPT
|
|
|
|
|
2022-11-14 01:25:24 +00:00
|
|
|
List AP clients (MAC, IP and RSSI) with command RgxClients on ESP32
|
2022-11-12 22:15:57 +00:00
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
|
2021-08-01 16:48:19 +01:00
|
|
|
An example full static configuration:
|
|
|
|
#define USE_WIFI_RANGE_EXTENDER
|
|
|
|
#define USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-02 01:25:32 +01:00
|
|
|
#define WIFI_RGX_STATE 1
|
|
|
|
#define WIFI_RGX_NAPT 1
|
2021-08-01 16:48:19 +01:00
|
|
|
#define WIFI_RGX_SSID "rangeextender"
|
|
|
|
#define WIFI_RGX_PASSWORD "securepassword"
|
|
|
|
#define WIFI_RGX_IP_ADDRESS "10.99.1.1"
|
|
|
|
#define WIFI_RGX_SUBNETMASK "255.255.255.0"
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
|
|
|
|
A full command to enable the Range Extender, including with NAPT could be:
|
|
|
|
Backlog RgxSSID rangeextender ; RgxPassword securepassword ; RgxAddress 192.168.123.1 ; RgxSubnet 255.255.255.0; RgxState 1 ; RgxNAPT 1
|
|
|
|
|
2021-08-01 16:48:19 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
#define XDRV_58 58
|
|
|
|
|
|
|
|
// Memory usage at 512: Heap from 30136 to 17632: 12504
|
|
|
|
// Memory usage at 128: Heap from 30136 to 26848: 3288
|
2021-08-02 01:25:32 +01:00
|
|
|
#define NAPT 128 // IP_NAPT_MAX: 512
|
|
|
|
#define NAPT_PORT 10 // IP_PORTMAP_MAX: 32
|
2021-08-01 16:48:19 +01:00
|
|
|
|
|
|
|
#warning **** USE_WIFI_RANGE_EXTENDER is enabled ****
|
|
|
|
|
|
|
|
#ifdef ESP8266
|
2021-08-02 13:08:40 +01:00
|
|
|
#if LWIP_FEATURES
|
2021-08-01 16:48:19 +01:00
|
|
|
// All good
|
|
|
|
#else
|
|
|
|
#error LWIP_FEATURES required, add "-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH" to build_flags
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // LWIP_FEATURES
|
|
|
|
#endif // ESP8266
|
2021-08-01 16:48:19 +01:00
|
|
|
|
|
|
|
#ifdef ESP32
|
|
|
|
#ifdef CONFIG_LWIP_IP_FORWARD
|
|
|
|
// All good
|
|
|
|
#else
|
|
|
|
#error CONFIG_LWIP_IP_FORWARD not set, arduino-esp32 v2 or later required with CONFIG_LWIP_IP_FORWARD support
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // CONFIG_LWIP_IP_FORWARD
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
|
|
|
#ifdef CONFIG_LWIP_IPV4_NAPT
|
|
|
|
// All good
|
|
|
|
#else
|
|
|
|
#error CONFIG_LWIP_IPV4_NAPT not set, arduino-esp32 v2 or later required with CONFIG_LWIP_IPV4_NAPT support
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // CONFIG_LWIP_IPV4_NAPT
|
2024-09-27 19:16:28 +01:00
|
|
|
#endif // CONFIG_LWIP_IP_FORWARD
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP32
|
2021-08-01 16:48:19 +01:00
|
|
|
|
|
|
|
const char kDrvRgxCommands[] PROGMEM = "Rgx|" // Prefix
|
|
|
|
"State"
|
2021-08-02 01:25:32 +01:00
|
|
|
"|" D_CMND_SSID
|
|
|
|
"|" D_CMND_PASSWORD
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
|
|
|
"|"
|
|
|
|
"NAPT"
|
2022-11-15 17:53:38 +00:00
|
|
|
"|"
|
|
|
|
"Port"
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
|
2022-11-12 22:15:57 +00:00
|
|
|
"|"
|
|
|
|
"Clients"
|
2021-08-01 16:48:19 +01:00
|
|
|
"|"
|
|
|
|
"Address"
|
|
|
|
"|"
|
|
|
|
"Subnet";
|
|
|
|
|
|
|
|
void (*const DrvRgxCommand[])(void) PROGMEM = {
|
|
|
|
&CmndRgxState,
|
|
|
|
&CmndRgxSSID,
|
|
|
|
&CmndRgxPassword,
|
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
|
|
|
&CmndRgxNAPT,
|
2022-11-15 17:53:38 +00:00
|
|
|
&CmndRgxPort,
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
|
2022-11-12 22:15:57 +00:00
|
|
|
&CmndRgxClients,
|
2021-08-01 16:48:19 +01:00
|
|
|
&CmndRgxAddresses,
|
|
|
|
&CmndRgxAddresses,
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
|
|
|
#ifdef ESP8266
|
|
|
|
#include <lwip/napt.h>
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP8266
|
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-01 16:48:19 +01:00
|
|
|
|
|
|
|
#include <lwip/dns.h>
|
|
|
|
#ifdef ESP8266
|
|
|
|
#include <dhcpserver.h>
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP8266
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef ESP32
|
|
|
|
#include "lwip/lwip_napt.h"
|
|
|
|
#include <dhcpserver/dhcpserver.h>
|
2022-11-14 00:18:32 +00:00
|
|
|
#include "esp_wifi.h"
|
2024-09-27 19:16:28 +01:00
|
|
|
#include "esp_wifi_ap_get_sta_list.h"
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP32
|
2021-08-01 16:48:19 +01:00
|
|
|
|
|
|
|
#define RGX_NOT_CONFIGURED 0
|
|
|
|
#define RGX_FORCE_CONFIGURE 1
|
|
|
|
#define RGX_CONFIGURED 2
|
|
|
|
#define RGX_CONFIG_INCOMPLETE 3
|
|
|
|
#define RGX_SETUP_NAPT 4
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
uint8_t status = RGX_NOT_CONFIGURED;
|
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
|
|
|
bool napt_enabled = false;
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-01 16:48:19 +01:00
|
|
|
} TRgxSettings;
|
|
|
|
|
|
|
|
TRgxSettings RgxSettings;
|
|
|
|
|
2022-11-20 15:28:59 +00:00
|
|
|
// externalize to be able to protect Rgx AP from teardown
|
|
|
|
bool RgxApUp()
|
|
|
|
{
|
|
|
|
return RgxSettings.status == RGX_CONFIGURED || RgxSettings.status == RGX_SETUP_NAPT;
|
|
|
|
}
|
|
|
|
|
2021-08-01 16:48:19 +01:00
|
|
|
// Check the current configuration is complete, updating RgxSettings.status
|
|
|
|
void RgxCheckConfig(void)
|
|
|
|
{
|
|
|
|
if (
|
|
|
|
strlen(SettingsText(SET_RGX_SSID)) > 0 &&
|
|
|
|
strlen(SettingsText(SET_RGX_PASSWORD)) >= 8 &&
|
|
|
|
Settings->ipv4_rgx_address &&
|
|
|
|
Settings->ipv4_rgx_subnetmask)
|
|
|
|
{
|
|
|
|
if (RgxSettings.status != RGX_FORCE_CONFIGURE)
|
|
|
|
{
|
|
|
|
RgxSettings.status = RGX_NOT_CONFIGURED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RgxSettings.status = RGX_CONFIG_INCOMPLETE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-12 22:15:57 +00:00
|
|
|
void CmndRgxClients(void)
|
|
|
|
{
|
2022-11-14 22:56:38 +00:00
|
|
|
Response_P(PSTR("{\"RgxClients\":{"));
|
|
|
|
const char *sep = "";
|
|
|
|
|
|
|
|
#if defined(ESP32)
|
2022-11-12 22:15:57 +00:00
|
|
|
wifi_sta_list_t wifi_sta_list = {0};
|
2024-09-27 19:16:28 +01:00
|
|
|
wifi_sta_mac_ip_list_t wifi_sta_mac_ip_list = {0};
|
2022-11-14 00:47:00 +00:00
|
|
|
|
2022-11-12 22:15:57 +00:00
|
|
|
esp_wifi_ap_get_sta_list(&wifi_sta_list);
|
2024-09-27 19:16:28 +01:00
|
|
|
esp_wifi_ap_get_sta_list_with_ip(&wifi_sta_list, &wifi_sta_mac_ip_list);
|
2022-11-12 22:15:57 +00:00
|
|
|
|
2024-09-27 19:16:28 +01:00
|
|
|
for (int i=0; i<wifi_sta_mac_ip_list.num; i++)
|
2022-11-12 22:15:57 +00:00
|
|
|
{
|
2024-09-27 19:16:28 +01:00
|
|
|
const uint8_t *m = wifi_sta_mac_ip_list.sta[i].mac;
|
2022-11-14 12:02:04 +00:00
|
|
|
ResponseAppend_P(PSTR("%s\"%02X%02X%02X%02X%02X%02X\":{\"" D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_RSSI "\":%d}"),
|
2024-09-27 19:16:28 +01:00
|
|
|
sep, m[0], m[1], m[2], m[3], m[4], m[5], wifi_sta_mac_ip_list.sta[i].ip, wifi_sta_list.sta[i].rssi);
|
2022-11-12 22:15:57 +00:00
|
|
|
sep = ",";
|
|
|
|
}
|
2022-11-14 22:56:38 +00:00
|
|
|
#elif defined(ESP8266)
|
|
|
|
struct station_info *station = wifi_softap_get_station_info();
|
|
|
|
while (station)
|
|
|
|
{
|
|
|
|
const uint8_t *m = station->bssid;
|
|
|
|
ResponseAppend_P(PSTR("%s\"%02X%02X%02X%02X%02X%02X\":{\"" D_CMND_IPADDRESS "\":\"%_I\"}"),
|
|
|
|
sep, m[0], m[1], m[2], m[3], m[4], m[5], station->ip.addr);
|
|
|
|
sep = ",";
|
|
|
|
station = STAILQ_NEXT(station, next);
|
|
|
|
}
|
|
|
|
wifi_softap_free_station_info();
|
|
|
|
#endif
|
|
|
|
|
2022-11-14 01:25:24 +00:00
|
|
|
ResponseAppend_P(PSTR("}}"));
|
2022-11-12 22:15:57 +00:00
|
|
|
}
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
void CmndRgxState(void)
|
|
|
|
{
|
|
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1))
|
|
|
|
{
|
|
|
|
if (Settings->sbflag1.range_extender != XdrvMailbox.payload)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
Settings->sbflag1.range_extender = XdrvMailbox.payload;
|
2021-08-02 01:25:32 +01:00
|
|
|
if (0 == XdrvMailbox.payload)
|
|
|
|
{ // Turn off
|
2021-08-01 16:48:19 +01:00
|
|
|
TasmotaGlobal.restart_flag = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ResponseCmndStateText(Settings->sbflag1.range_extender);
|
|
|
|
}
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
void CmndRgxAddresses(void)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
char network_address[22];
|
|
|
|
ext_snprintf_P(network_address, sizeof(network_address), PSTR(" (%_I)"), (uint32_t)NetworkAddress());
|
|
|
|
uint32_t ipv4_address;
|
2021-08-02 01:25:32 +01:00
|
|
|
if (ParseIPv4(&ipv4_address, XdrvMailbox.data))
|
|
|
|
{
|
|
|
|
if (XdrvMailbox.command[3] == 'S') // Subnet
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
Settings->ipv4_rgx_subnetmask = ipv4_address;
|
2021-08-02 01:25:32 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
Settings->ipv4_rgx_address = ipv4_address;
|
|
|
|
}
|
|
|
|
RgxSettings.status = RGX_FORCE_CONFIGURE;
|
|
|
|
}
|
|
|
|
ResponseRgxConfig();
|
|
|
|
}
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
void CmndRgxSSID(void)
|
|
|
|
{
|
|
|
|
if (XdrvMailbox.data_len > 0)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
SettingsUpdateText(SET_RGX_SSID, (SC_CLEAR == Shortcut()) ? "" : XdrvMailbox.data);
|
2021-08-02 01:25:32 +01:00
|
|
|
RgxSettings.status = RGX_FORCE_CONFIGURE;
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
|
|
|
ResponseRgxConfig();
|
|
|
|
}
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
void CmndRgxPassword(void)
|
|
|
|
{
|
|
|
|
if (XdrvMailbox.data_len > 0)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
SettingsUpdateText(SET_RGX_PASSWORD, (SC_CLEAR == Shortcut()) ? "" : XdrvMailbox.data);
|
2021-08-02 01:25:32 +01:00
|
|
|
RgxSettings.status = RGX_FORCE_CONFIGURE;
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
|
|
|
ResponseRgxConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-02 01:25:32 +01:00
|
|
|
void CmndRgxNAPT(void)
|
|
|
|
{
|
|
|
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1))
|
|
|
|
{
|
|
|
|
if (Settings->sbflag1.range_extender_napt != XdrvMailbox.payload)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
Settings->sbflag1.range_extender_napt = XdrvMailbox.payload;
|
2021-08-02 01:25:32 +01:00
|
|
|
if (0 == XdrvMailbox.payload)
|
|
|
|
{ // Turn off
|
|
|
|
// ESP32 does not disable reliably, reboot to ensure a complete disable of NAPT
|
|
|
|
// rebooting also completely frees up the used RAM
|
|
|
|
TasmotaGlobal.restart_flag = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RgxSettings.status = RGX_FORCE_CONFIGURE;
|
|
|
|
}
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ResponseCmndStateText(Settings->sbflag1.range_extender_napt);
|
2022-11-15 17:53:38 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 11:47:53 +00:00
|
|
|
// CmndRgxPort helper: Do port map and set response if successful
|
|
|
|
void CmndRgxPortMap(uint8_t proto, uint16_t gw_port, uint32_t dst_ip, uint16_t dst_port)
|
|
|
|
{
|
|
|
|
uint32_t gw_ip = (uint32_t)WiFi.localIP();
|
|
|
|
if (ip_portmap_add(proto, gw_ip, gw_port, dst_ip, dst_port))
|
|
|
|
{
|
|
|
|
Response_P(PSTR("OK %s %_I:%u -> %_I:%u"),
|
|
|
|
(proto == IP_PROTO_TCP) ? "TCP" : "UDP", gw_ip, gw_port, dst_ip, dst_port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CmndRgxPort helper: If mac from esp list and mac from command parameters are the same try port map and return true
|
|
|
|
bool CmndRgxPortMapCheck(const uint8_t *mac, const char *parm_mac, uint8_t proto, uint16_t gw_port, uint32_t dst_ip, uint16_t dst_port)
|
|
|
|
{
|
|
|
|
char list_mac[13];
|
|
|
|
snprintf(list_mac, sizeof(list_mac), PSTR("%02X%02X%02X%02X%02X%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
|
|
if (strcasecmp(list_mac, parm_mac) == 0)
|
|
|
|
{
|
|
|
|
CmndRgxPortMap(proto, gw_port, dst_ip, dst_port);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-11-15 17:53:38 +00:00
|
|
|
void CmndRgxPort(void)
|
|
|
|
{
|
2022-11-19 11:47:53 +00:00
|
|
|
char *tok, *state, *parm_addr;
|
2022-11-15 17:53:38 +00:00
|
|
|
uint16_t gw, dst;
|
|
|
|
uint8_t proto = 0;
|
|
|
|
|
|
|
|
Response_P(PSTR("ERROR"));
|
|
|
|
|
2022-11-19 11:47:53 +00:00
|
|
|
// Parameter parsing
|
2022-11-15 17:53:38 +00:00
|
|
|
if (ArgC()!=4) return;
|
|
|
|
if ((tok = strtok_r(XdrvMailbox.data, ", ", &state)) == 0) return;
|
|
|
|
if (strcasecmp("TCP", tok) == 0) proto = IP_PROTO_TCP;
|
|
|
|
if (strcasecmp("UDP", tok) == 0) proto = IP_PROTO_UDP;
|
|
|
|
if (!proto) return;
|
|
|
|
if ((tok = strtok_r(0, ", ", &state)) == 0) return;
|
|
|
|
if ((gw = strtoul(tok, nullptr, 0)) == 0) return;
|
2022-11-19 11:47:53 +00:00
|
|
|
if ((parm_addr = strtok_r(0, ", ", &state)) == 0) return;
|
2022-11-15 17:53:38 +00:00
|
|
|
if ((tok = strtok_r(0, ", ", &state)) == 0) return;
|
|
|
|
if ((dst = strtoul(tok, nullptr, 0)) == 0) return;
|
|
|
|
|
2022-11-19 11:47:53 +00:00
|
|
|
// If forward address is an ip, then just do it...
|
|
|
|
// Useful for static IPs not used by the range extender dhcp server
|
|
|
|
// On ESP8266 the default dhcp ip range to avoid is .100-.200
|
|
|
|
// On ESP32 the default dhcp ip range to avoid is .2-.11
|
|
|
|
IPAddress ip;
|
|
|
|
if (ip.fromString(parm_addr))
|
|
|
|
{
|
|
|
|
CmndRgxPortMap(proto, gw, (uint32_t)ip, dst);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Forward address is a mac, find the associated ip...
|
2022-11-16 22:51:54 +00:00
|
|
|
#if defined(ESP32)
|
2022-11-15 17:53:38 +00:00
|
|
|
wifi_sta_list_t wifi_sta_list = {0};
|
2024-09-27 19:16:28 +01:00
|
|
|
wifi_sta_mac_ip_list_t wifi_sta_mac_ip_list = {0};
|
2022-11-15 17:53:38 +00:00
|
|
|
|
|
|
|
esp_wifi_ap_get_sta_list(&wifi_sta_list);
|
2024-09-27 19:16:28 +01:00
|
|
|
esp_wifi_ap_get_sta_list_with_ip(&wifi_sta_list, &wifi_sta_mac_ip_list);
|
2022-11-15 17:53:38 +00:00
|
|
|
|
2024-09-27 19:16:28 +01:00
|
|
|
for (int i=0; i<wifi_sta_mac_ip_list.num; i++)
|
2022-11-15 17:53:38 +00:00
|
|
|
{
|
2024-09-27 19:16:28 +01:00
|
|
|
if (CmndRgxPortMapCheck(wifi_sta_mac_ip_list.sta[i].mac, parm_addr, proto, gw, wifi_sta_mac_ip_list.sta[i].ip.addr, dst))
|
2022-11-15 17:53:38 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-11-16 22:51:54 +00:00
|
|
|
#elif defined(ESP8266)
|
|
|
|
struct station_info *station = wifi_softap_get_station_info();
|
|
|
|
while (station)
|
|
|
|
{
|
2022-11-19 11:47:53 +00:00
|
|
|
if (CmndRgxPortMapCheck(station->bssid, parm_addr, proto, gw, station->ip.addr, dst))
|
2022-11-16 22:51:54 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
station = STAILQ_NEXT(station, next);
|
|
|
|
}
|
|
|
|
wifi_softap_free_station_info();
|
|
|
|
#endif // ESP8266
|
2022-11-15 17:53:38 +00:00
|
|
|
}
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-01 16:48:19 +01:00
|
|
|
|
|
|
|
void ResponseRgxConfig(void)
|
|
|
|
{
|
|
|
|
RgxCheckConfig();
|
2023-12-25 08:13:32 +00:00
|
|
|
Response_P(PSTR("{\"Rgx\":{\"Valid\":\"%s\",\"" D_CMND_SSID "\":\"%s\",\"" D_CMND_PASSWORD "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\"}}"),
|
2021-08-01 16:48:19 +01:00
|
|
|
(RgxSettings.status == RGX_CONFIG_INCOMPLETE) ? "false" : "true",
|
|
|
|
EscapeJSONString(SettingsText(SET_RGX_SSID)).c_str(),
|
|
|
|
EscapeJSONString(SettingsText(SET_RGX_PASSWORD)).c_str(),
|
|
|
|
Settings->ipv4_rgx_address,
|
|
|
|
Settings->ipv4_rgx_subnetmask);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rngxSetup()
|
|
|
|
{
|
|
|
|
// Check we have a complete config first
|
|
|
|
RgxCheckConfig();
|
|
|
|
if (RgxSettings.status == RGX_CONFIG_INCOMPLETE)
|
|
|
|
{
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("RGX: Range Extender config incomplete"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef ESP8266
|
|
|
|
dhcps_set_dns(0, WiFi.dnsIP(0));
|
|
|
|
dhcps_set_dns(1, WiFi.dnsIP(1));
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP8266
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef ESP32
|
|
|
|
esp_err_t err;
|
2024-09-27 19:16:28 +01:00
|
|
|
esp_netif_t* esp_netif_STA = get_esp_interface_netif(ESP_IF_WIFI_STA);
|
|
|
|
esp_netif_t* esp_netif_AP = get_esp_interface_netif(ESP_IF_WIFI_AP);
|
|
|
|
esp_netif_dns_info_t ip_dns;
|
2021-08-01 16:48:19 +01:00
|
|
|
|
2024-09-27 19:16:28 +01:00
|
|
|
err = esp_netif_dhcps_stop(esp_netif_AP);
|
|
|
|
err = esp_netif_get_dns_info(esp_netif_STA, ESP_NETIF_DNS_MAIN, &ip_dns);
|
|
|
|
err = esp_netif_set_dns_info(esp_netif_AP, ESP_NETIF_DNS_MAIN, &ip_dns);
|
2021-08-01 16:48:19 +01:00
|
|
|
dhcps_offer_t opt_val = OFFER_DNS; // supply a dns server via dhcps
|
2024-09-27 19:16:28 +01:00
|
|
|
err = esp_netif_dhcps_option(esp_netif_AP, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &opt_val, 1);
|
|
|
|
err = esp_netif_dhcps_start(esp_netif_AP);
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP32
|
2021-08-01 16:48:19 +01:00
|
|
|
// WiFi.softAPConfig(EXTENDER_LOCAL_IP, EXTENDER_GATEWAY_IP, EXTENDER_SUBNET);
|
|
|
|
WiFi.softAPConfig(Settings->ipv4_rgx_address, Settings->ipv4_rgx_address, Settings->ipv4_rgx_subnetmask);
|
|
|
|
WiFi.softAP(SettingsText(SET_RGX_SSID), SettingsText(SET_RGX_PASSWORD));
|
2021-08-02 01:25:32 +01:00
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("RGX: WiFi Extender AP Enabled with SSID: %s"), WiFi.softAPSSID().c_str());
|
2021-08-01 16:48:19 +01:00
|
|
|
RgxSettings.status = RGX_SETUP_NAPT;
|
|
|
|
}
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
void rngxSetupNAPT(void)
|
|
|
|
{
|
|
|
|
// A short delay is required for enabling NAPT to work on the ESP32, hence a dedicated
|
|
|
|
// function called a second later
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-02 01:25:32 +01:00
|
|
|
if (Settings->sbflag1.range_extender_napt && !RgxSettings.napt_enabled)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef ESP8266
|
2021-08-02 01:25:32 +01:00
|
|
|
// ip_napt_init can only be called once, however device will reboot when disabled
|
|
|
|
// so no need to limit calls to init separately.
|
|
|
|
err_t ret = ip_napt_init(NAPT, NAPT_PORT);
|
|
|
|
if (ret == ERR_OK)
|
|
|
|
{
|
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("RGX: NAPT initialization complete"));
|
2021-08-01 16:48:19 +01:00
|
|
|
err_t ret = ip_napt_enable_no(SOFTAP_IF, 1);
|
2021-08-02 01:25:32 +01:00
|
|
|
if (ret == ERR_OK)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("RGX: NAPT Enabled"));
|
|
|
|
RgxSettings.napt_enabled = true;
|
|
|
|
}
|
|
|
|
}
|
2021-08-02 01:25:32 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
AddLog(LOG_LEVEL_ERROR, PSTR("RGX: NAPT initialization failed! (%d)"), ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // ESP8266
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef ESP32
|
|
|
|
ip_napt_enable(WiFi.softAPIP(), 1);
|
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("RGX: NAPT Enabled"));
|
|
|
|
RgxSettings.napt_enabled = true;
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP32
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
2021-08-02 01:25:32 +01:00
|
|
|
// This code path is no longer used as device will reboot to disable NAPT, maybe
|
|
|
|
// restored when working correctly on ESP32
|
|
|
|
/*
|
|
|
|
else if (!Settings->sbflag1.range_extender_napt && RgxSettings.napt_enabled)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef ESP8266
|
|
|
|
err_t ret = ip_napt_enable_no(SOFTAP_IF, 0);
|
2021-08-02 01:25:32 +01:00
|
|
|
if (ret == ERR_OK)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
AddLog(LOG_LEVEL_INFO, "RGX: NAPT Disabled");
|
|
|
|
RgxSettings.napt_enabled = false;
|
|
|
|
}
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP8266
|
2021-08-01 16:48:19 +01:00
|
|
|
#ifdef ESP32
|
|
|
|
ip_napt_enable(WiFi.softAPIP(), 0);
|
|
|
|
AddLog(LOG_LEVEL_INFO, "RGX: NAPT Disabled, reboot maybe required");
|
2021-08-02 01:25:32 +01:00
|
|
|
#endif // ESP32
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
2021-08-02 01:25:32 +01:00
|
|
|
*/
|
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
|
2021-08-01 16:48:19 +01:00
|
|
|
RgxSettings.status = RGX_CONFIGURED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Interface
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2022-11-11 09:44:56 +00:00
|
|
|
bool Xdrv58(uint32_t function)
|
2021-08-02 01:25:32 +01:00
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
bool result = false;
|
|
|
|
|
2021-08-02 01:25:32 +01:00
|
|
|
if (FUNC_COMMAND == function)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
result = DecodeCommand(kDrvRgxCommands, DrvRgxCommand);
|
|
|
|
}
|
2021-08-02 01:25:32 +01:00
|
|
|
else if (Settings->sbflag1.range_extender && !TasmotaGlobal.restart_flag)
|
|
|
|
{
|
2021-08-01 16:48:19 +01:00
|
|
|
switch (function)
|
|
|
|
{
|
|
|
|
case FUNC_PRE_INIT:
|
|
|
|
break;
|
|
|
|
case FUNC_EVERY_SECOND:
|
2021-08-08 06:51:30 +01:00
|
|
|
// AddLog(LOG_LEVEL_INFO, PSTR("RGX: XXX DEBUG: Wifi.status: %d, WiFi.getMode(): %d, RgxSettings.status: %d, link_count: %d"), Wifi.status, WiFi.getMode(), RgxSettings.status, Wifi.link_count);
|
2021-08-01 16:48:19 +01:00
|
|
|
if (RgxSettings.status == RGX_NOT_CONFIGURED && Wifi.status == WL_CONNECTED)
|
|
|
|
{
|
|
|
|
// Setup only if WiFi in STA only mode
|
|
|
|
if (WiFi.getMode() == WIFI_STA)
|
|
|
|
{
|
|
|
|
// Connecting for the first time, setup WiFi
|
|
|
|
rngxSetup();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RgxSettings.status = RGX_CONFIGURED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (RgxSettings.status == RGX_FORCE_CONFIGURE && Wifi.status == WL_CONNECTED)
|
|
|
|
{
|
|
|
|
rngxSetup();
|
|
|
|
}
|
|
|
|
else if (RgxSettings.status == RGX_SETUP_NAPT)
|
|
|
|
{
|
2021-08-02 01:25:32 +01:00
|
|
|
// Call NAPT a second later as ESP32 requires short delay
|
2021-08-01 16:48:19 +01:00
|
|
|
rngxSetupNAPT();
|
|
|
|
}
|
|
|
|
else if (RgxSettings.status == RGX_CONFIGURED)
|
|
|
|
{
|
2022-11-16 16:28:03 +00:00
|
|
|
if (Wifi.status == WL_CONNECTED && WiFi.getMode() != WIFI_AP_STA)
|
2021-08-01 16:48:19 +01:00
|
|
|
{
|
2022-11-16 16:28:03 +00:00
|
|
|
// Should not happen... our AP is gone and only a restart will get it back properly
|
|
|
|
AddLog(LOG_LEVEL_INFO, PSTR("RGX: WiFi mode is %d not %d. Restart..."), WiFi.getMode(), WIFI_AP_STA);
|
|
|
|
TasmotaGlobal.restart_flag = 2;
|
2021-08-08 06:51:30 +01:00
|
|
|
}
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
|
|
|
break;
|
2023-12-27 21:03:56 +00:00
|
|
|
case FUNC_ACTIVE:
|
|
|
|
result = true;
|
|
|
|
break;
|
2021-08-01 16:48:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-12-25 08:13:32 +00:00
|
|
|
#endif // USE_WIFI_RANGE_EXTENDER
|