[realtek-ambz] Fix WiFi AP mode and DNS

This commit is contained in:
Kuba Szczodrzyński
2023-03-18 13:27:16 +01:00
parent 250e67ab1f
commit 201db4668e
9 changed files with 305 additions and 129 deletions

View File

@@ -71,6 +71,12 @@ class WiFiClass {
static uint8_t calculateSubnetCIDR(IPAddress subnetMask);
static String macToString(uint8_t *mac);
static void resetNetworkInfo(WiFiNetworkInfo &info);
private: /* WiFiGeneric.cpp */
bool restoreSTAConfig(const WiFiNetworkInfo &info);
bool restoreAPConfig(const WiFiNetworkInfo &info);
protected: /* WiFiEvents.cpp */
static std::vector<EventHandler> handlers;

View File

@@ -119,3 +119,36 @@ String WiFiClass::macToString(uint8_t *mac) {
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return macStr;
}
void WiFiClass::resetNetworkInfo(WiFiNetworkInfo &info) {
LT_VM(WIFI, "Resetting network info: %s", info.ssid);
free(info.ssid);
free(info.password);
free(info.bssid);
// wipe the structure, except IP addresses
memset(&info, 0x00, sizeof(WiFiNetworkInfo) - 5 * sizeof(uint32_t));
}
bool WiFiClass::restoreSTAConfig(const WiFiNetworkInfo &info) {
LT_DM(WIFI, "Restoring %s config: %s", "STA", info.ssid);
if (!info.ssid)
return false;
if (info.localIP) {
LT_DM(WIFI, "Restoring STA IP config");
if (!config(info.localIP, info.gateway, info.subnet, info.dns1, info.dns2))
return false;
}
return begin(info.ssid, info.password, info.channel, info.bssid);
}
bool WiFiClass::restoreAPConfig(const WiFiNetworkInfo &info) {
LT_DM(WIFI, "Restoring %s config: %s", "AP", info.ssid);
if (!info.ssid)
return false;
if (info.localIP) {
LT_DM(WIFI, "Restoring AP IP config");
if (!softAPConfig(info.localIP, info.gateway, info.subnet))
return false;
}
return softAP(info.ssid, info.password, info.channel, info.ssidHidden);
}

View File

@@ -128,6 +128,20 @@ typedef enum {
WIFI_REASON_ROAMING = 207,
} wifi_err_reason_t;
typedef struct {
char *ssid;
char *password;
uint8_t *bssid;
bool ssidHidden;
int channel;
int auth;
uint32_t localIP;
uint32_t subnet;
uint32_t gateway;
uint32_t dns1;
uint32_t dns2;
} WiFiNetworkInfo;
typedef struct {
char *ssid;
WiFiAuthMode auth;

View File

@@ -2,28 +2,7 @@
#include "WiFiPrivate.h"
// TODO move these to WiFiData
rtw_network_info_t wifi = {0};
rtw_ap_info_t ap = {0};
rtw_wifi_setting_t wifi_setting;
unsigned char sta_password[65] = {0};
unsigned char ap_password[65] = {0};
void reset_wifi_struct(void) {
memset(wifi.ssid.val, 0, sizeof(wifi.ssid.val));
memset(wifi.bssid.octet, 0, ETH_ALEN);
memset(sta_password, 0, sizeof(sta_password));
memset(ap_password, 0, sizeof(ap_password));
wifi.ssid.len = 0;
wifi.password = NULL;
wifi.password_len = 0;
wifi.key_id = -1;
memset(ap.ssid.val, 0, sizeof(ap.ssid.val));
ap.ssid.len = 0;
ap.password = NULL;
ap.password_len = 0;
ap.channel = 1;
}
WiFiClass::WiFiClass() {
data = (WiFiData *)calloc(1, sizeof(WiFiData));

View File

@@ -14,22 +14,23 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo
return WL_CONNECT_FAILED;
LT_HEAP_I();
vTaskDelay(20);
strcpy((char *)ap.ssid.val, ssid);
ap.ssid.len = strlen(ssid);
ap.channel = channel;
WiFiNetworkInfo &info = DATA->ap;
if (info.ssid != ssid)
// free network info, if not called from restoreAPConfig()
resetNetworkInfo(info);
ap.security_type = RTW_SECURITY_OPEN;
ap.password = NULL;
ap.password_len = 0;
if (info.ssid != ssid)
info.ssid = strdup(ssid);
info.ssidHidden = ssidHidden;
info.channel = channel;
info.auth = RTW_SECURITY_OPEN;
if (passphrase) {
strcpy((char *)ap_password, passphrase);
ap.security_type = RTW_SECURITY_WPA2_AES_PSK;
ap.password = ap_password;
ap.password_len = strlen(passphrase);
if (info.password != passphrase)
info.password = strdup(passphrase);
info.auth = RTW_SECURITY_WPA2_AES_PSK;
}
dhcps_deinit();
@@ -39,26 +40,24 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo
int ret;
if (!ssidHidden) {
ret = wifi_start_ap(
(char *)ap.ssid.val,
ap.security_type,
(char *)ap.password,
ap.ssid.len,
ap.password_len,
ap.channel
info.ssid,
(rtw_security_t)info.auth,
info.password,
strlen(info.ssid),
strlen(info.password),
info.channel
);
} else {
ret = wifi_start_ap_with_hidden_ssid(
(char *)ap.ssid.val,
ap.security_type,
(char *)ap.password,
ap.ssid.len,
ap.password_len,
ap.channel
info.ssid,
(rtw_security_t)info.auth,
info.password,
strlen(info.ssid),
strlen(info.password),
info.channel
);
}
wifi_indication(WIFI_EVENT_CONNECT, NULL, ARDUINO_EVENT_WIFI_AP_START, -2);
if (ret < 0) {
LT_EM(WIFI, "SoftAP failed; ret=%d", ret);
return false;
@@ -72,7 +71,7 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo
while (1) {
if (wext_get_ssid(ifname, essid) > 0) {
if (strcmp((const char *)essid, (const char *)ap.ssid.val) == 0)
if (strcmp((const char *)essid, info.ssid) == 0)
break;
}
@@ -83,27 +82,28 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo
timeout--;
}
wifi_indication(WIFI_EVENT_CONNECT, NULL, ARDUINO_EVENT_WIFI_AP_START, -2);
dhcps_init(ifs);
dns_server_deinit();
return true;
}
bool WiFiClass::softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) {
if (!enableAP(true))
return false;
struct netif *ifs = NETIF_RTW_AP;
WiFiNetworkInfo &info = DATA->ap;
struct netif *ifs = NETIF_RTW_AP;
struct ip_addr ipaddr, netmask, gw;
ipaddr.addr = localIP;
netmask.addr = subnet;
gw.addr = gateway;
ipaddr.addr = info.localIP = localIP;
netmask.addr = info.subnet = subnet;
gw.addr = info.gateway = gateway;
netif_set_addr(ifs, &ipaddr, &netmask, &gw);
return true;
}
bool WiFiClass::softAPdisconnect(bool wifiOff) {
// TODO implement wifi_restart_ap
if (wifiOff)
return enableAP(false);
return true;
return enableAP(false);
}
uint8_t WiFiClass::softAPgetStationNum() {
@@ -115,11 +115,11 @@ uint8_t WiFiClass::softAPgetStationNum() {
}
IPAddress WiFiClass::softAPIP() {
return LwIP_GetIP(NETIF_RTW_AP);
return netif_ip_addr4(NETIF_RTW_AP)->addr;
}
IPAddress WiFiClass::softAPSubnetMask() {
return LwIP_GetMASK(NETIF_RTW_AP);
return netif_ip_netmask4(NETIF_RTW_AP)->addr;
}
const char *WiFiClass::softAPgetHostname() {
@@ -132,19 +132,17 @@ bool WiFiClass::softAPsetHostname(const char *hostname) {
}
uint8_t *WiFiClass::softAPmacAddress(uint8_t *mac) {
uint8_t *macLocal = LwIP_GetMAC(NETIF_RTW_AP);
memcpy(mac, macLocal, ETH_ALEN);
free(macLocal);
memcpy(mac, NETIF_RTW_AP->hwaddr, ETH_ALEN);
return mac;
}
String WiFiClass::softAPmacAddress(void) {
uint8_t mac[ETH_ALEN];
macAddress(mac);
softAPmacAddress(mac);
return macToString(mac);
}
const String WiFiClass::softAPSSID(void) {
wifi_get_setting(NETNAME_AP, &wifi_setting);
wext_get_ssid(NETNAME_AP, wifi_setting.ssid);
return (char *)wifi_setting.ssid;
}

View File

@@ -17,23 +17,128 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
// initialize wifi first
LT_IM(WIFI, "Initializing LwIP");
LwIP_Init();
reset_wifi_struct();
DATA->initialized = true;
}
LT_HEAP_I();
if (getMode()) {
// stop wifi to change mode
LT_DM(WIFI, "Stopping WiFi to change mode");
if (wifi_off() != RTW_SUCCESS)
goto error;
vTaskDelay(20);
if (mode == WIFI_MODE_NULL)
goto error;
WiFiMode currentMode = getMode();
WiFiNetworkInfo &staInfo = DATA->sta;
WiFiNetworkInfo &apInfo = DATA->ap;
bool reenableSTA = false;
bool reenableAP = false;
if (mode == WIFI_MODE_APSTA) {
if (currentMode == WIFI_MODE_STA) {
// adding AP mode doesn't seem to work fine:
// - STA -> AP+STA
LT_DM(WIFI, "STA was enabled: %s", staInfo.ssid);
reenableSTA = true;
}
if (currentMode == WIFI_MODE_AP) {
// restart AP mode later, as wifi has to be stopped first:
// - AP -> AP+STA
LT_DM(WIFI, "AP was enabled: %s", apInfo.ssid);
reenableAP = true;
}
}
if (wifi_on((rtw_mode_t)mode) != RTW_SUCCESS) {
LT_EM(WIFI, "Error while changing mode(%u)", mode);
goto error;
if (reenableSTA || reenableAP || mode == WIFI_MODE_NULL || currentMode == WIFI_MODE_AP ||
currentMode && mode == WIFI_MODE_AP) {
// must stop wifi first:
// - STA -> NULL
// - STA -> AP
// - STA -> AP+STA
// - AP -> NULL
// - AP -> STA
// - AP -> AP+STA
// - AP+STA -> NULL
// - AP+STA -> AP
LT_DM(WIFI, "Stopping WiFi to change mode");
if (wifi_off() != RTW_SUCCESS) {
LT_EM(WIFI, "Error while changing mode(%u)", mode);
goto error;
}
rltk_wlan_deinit_fastly();
rltk_wlan_rf_off();
init_event_callback_list();
vTaskDelay(20);
currentMode = getMode();
}
if (currentMode == WIFI_MODE_NULL && mode != WIFI_MODE_NULL) {
// wifi is not running, enable it the usual way:
// - NULL -> STA
// - NULL -> AP
// - NULL -> AP+STA
if (wifi_on((rtw_mode_t)mode) != RTW_SUCCESS) {
LT_EM(WIFI, "Error while changing mode(%u)", mode);
goto error;
}
} else {
// just enable/disable wlan1:
// - STA -> AP+STA - unused (wifi reset required)
// - AP+STA -> STA
wifi_mode = mode;
/* if (ap == WLMODE_ENABLE) {
LT_DM(WIFI, "Mode: %s ENABLE", WLAN1_NAME);
rltk_wlan_init(WLAN1_IDX, RTW_MODE_AP);
rltk_wlan_start(WLAN1_IDX);
uint32_t timeout = 20;
while (1) {
if (rltk_wlan_running(WLAN1_IDX)) {
wifi_set_country_code();
break;
}
if (timeout == 0) {
LT_EM(WIFI, "Error while changing mode(%u)", mode);
goto error;
}
vTaskDelay(1 * configTICK_RATE_HZ);
timeout--;
}
netif_set_up(WLAN1_NETIF);
netif_set_link_up(WLAN1_NETIF);
} */
if (ap == WLMODE_DISABLE) {
LT_DM(WIFI, "Mode: %s DISABLE", WLAN1_NAME);
netif_set_link_down(WLAN1_NETIF);
netif_set_down(WLAN1_NETIF);
rltk_stop_softap(WLAN1_NAME);
rltk_wlan_init(WLAN1_IDX, RTW_MODE_NONE);
wext_set_mode(WLAN1_NAME, IW_MODE_INFRA);
}
vTaskDelay(50);
}
if (mode & WIFI_MODE_AP) {
// indicate that the interface is an AP
// use NETNAME_AP to retrieve the actual iface name (wlan0/wlan1)
// (this is determined by STA bit being set in wifi_mode)
wext_set_mode(NETNAME_AP, IW_MODE_MASTER);
}
if (sta == WLMODE_DISABLE) {
// mark that STA mode has been disabled manually
free(staInfo.ssid);
staInfo.ssid = NULL;
}
if (ap == WLMODE_DISABLE) {
// mark that AP mode has been disabled manually
free(apInfo.ssid);
apInfo.ssid = NULL;
}
// force checking WiFi mode again (which will update wifi_mode)
getMode();
if (reenableSTA) {
// restart STA mode from previously used config (if set)
if (!restoreSTAConfig(staInfo))
LT_EM(WIFI, "Couldn't restore STA mode: %s", staInfo.ssid);
}
if (reenableAP) {
// restart AP mode from previously used config (if set)
if (!restoreAPConfig(apInfo))
LT_EM(WIFI, "Couldn't restore AP mode: %s", apInfo.ssid);
}
// send STA start/stop events and AP stop event (start is handled in softAP())
@@ -60,11 +165,30 @@ error:
WiFiMode WiFiClass::getMode() {
if (!DATA->initialized)
return WIFI_MODE_NULL;
return (WiFiMode)wifi_mode;
uint8_t wlan0_state = rltk_wlan_running(WLAN0_IDX);
uint8_t wlan1_state = rltk_wlan_running(WLAN1_IDX);
wifi_mode = (wifi_mode_t)wlan0_state;
LT_DM(WIFI, "WLAN: %s=%u, %s=%u", WLAN0_NAME, wlan0_state, WLAN1_NAME, wlan1_state);
if (wlan1_state) {
if (netif_is_up(WLAN1_NETIF))
wifi_mode = (wifi_mode_t)(WIFI_MODE_AP | wlan0_state);
} else {
wifi_mode = (wifi_mode_t)(wlan0_state);
int mode = 0;
// check wlan0 mode to determine if it's an AP
if (wlan0_state)
wext_get_mode(WLAN0_NAME, &mode);
if (mode == IW_MODE_MASTER)
wifi_mode = (wifi_mode_t)(wifi_mode << 1);
}
return wifi_mode;
}
WiFiStatus WiFiClass::status() {
if (wifi_is_connected_to_ap() == 0) {
if (rltk_wlan_is_connected_to_ap() == 0) {
return WL_CONNECTED;
} else {
return WL_DISCONNECTED;

View File

@@ -26,31 +26,40 @@ extern "C" {
extern struct netif xnetif[NET_IF_NUM];
// dhcps.c
extern void dns_server_init(struct netif *pnetif);
extern void dns_server_deinit(void);
// wifi_util.c
extern void rltk_stop_softap(const char *ifname);
extern void rltk_suspend_softap(const char *ifname);
extern void rltk_suspend_softap_beacon(const char *ifname);
} // extern "C"
// WiFi.cpp
extern rtw_network_info_t wifi;
extern rtw_ap_info_t ap;
extern rtw_wifi_setting_t wifi_setting;
extern unsigned char sta_password[65];
extern unsigned char ap_password[65];
extern void reset_wifi_struct(void);
extern wifi_mode_t wifi_mode;
extern WiFiAuthMode securityTypeToAuthMode(uint8_t type);
// WiFiEvents.cpp
extern void startWifiTask();
extern void handleRtwEvent(uint16_t event, char *data, int len, int flags);
#define NETIF_RTW_STA &xnetif[RTW_STA_INTERFACE]
#define NETIF_RTW_AP (wifi_mode == WIFI_MODE_APSTA ? &xnetif[RTW_AP_INTERFACE] : NETIF_RTW_STA)
#define WLAN0_NETIF &xnetif[RTW_STA_INTERFACE]
#define WLAN1_NETIF &xnetif[RTW_AP_INTERFACE]
#define NETIF_RTW_STA WLAN0_NETIF
#define NETIF_RTW_AP (wifi_mode & WIFI_MODE_STA ? WLAN1_NETIF : WLAN0_NETIF)
#define NETNAME_STA WLAN0_NAME
#define NETNAME_AP (wifi_mode == WIFI_MODE_APSTA ? WLAN1_NAME : WLAN0_NAME)
#define NETNAME_AP (wifi_mode & WIFI_MODE_STA ? WLAN1_NAME : WLAN0_NAME)
typedef struct {
bool initialized;
bool sleep;
SemaphoreHandle_t scanSem;
WiFiNetworkInfo sta;
WiFiNetworkInfo ap;
} WiFiData;
#define DATA ((WiFiData *)data)

View File

@@ -11,20 +11,20 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons
LT_HEAP_I();
memset(wifi.bssid.octet, 0, ETH_ALEN);
strcpy((char *)wifi.ssid.val, ssid);
wifi.ssid.len = strlen(ssid);
WiFiNetworkInfo &info = DATA->sta;
if (info.ssid != ssid)
// free network info, if not called from restoreSTAConfig()
resetNetworkInfo(info);
wifi.security_type = RTW_SECURITY_OPEN;
wifi.password = NULL;
wifi.password_len = 0;
wifi.key_id = 0;
if (info.ssid != ssid)
info.ssid = strdup(ssid);
info.channel = channel;
info.auth = RTW_SECURITY_OPEN;
if (passphrase) {
strcpy((char *)sta_password, passphrase);
wifi.security_type = RTW_SECURITY_WPA2_AES_PSK;
wifi.password = sta_password;
wifi.password_len = strlen(passphrase);
if (info.password != passphrase)
info.password = strdup(passphrase);
info.auth = RTW_SECURITY_WPA2_AES_PSK;
}
if (reconnect(bssid))
@@ -36,24 +36,26 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons
bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) {
if (!enableSTA(true))
return false;
WiFiNetworkInfo &info = DATA->sta;
struct ip_addr d1, d2;
d1.addr = dns1;
d2.addr = dns2;
if (dns1[0])
d1.addr = info.dns1 = dns1;
d2.addr = info.dns2 = dns2;
if (d1.addr)
dns_setserver(0, &d1);
if (dns2[0])
if (d2.addr)
dns_setserver(0, &d2);
if (!localIP[0]) {
info.localIP = 0;
LwIP_DHCP(0, DHCP_START);
return true;
}
struct netif *ifs = NETIF_RTW_STA;
struct ip_addr ipaddr, netmask, gw;
ipaddr.addr = localIP;
netmask.addr = subnet;
gw.addr = gateway;
ipaddr.addr = info.localIP = localIP;
netmask.addr = info.subnet = subnet;
gw.addr = info.gateway = gateway;
netif_set_addr(ifs, &ipaddr, &netmask, &gw);
LwIP_DHCP(0, DHCP_STOP);
return true;
@@ -62,31 +64,39 @@ bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, I
bool WiFiClass::reconnect(const uint8_t *bssid) {
int ret;
uint8_t dhcpRet;
WiFiNetworkInfo &info = DATA->sta;
LT_IM(WIFI, "Connecting to %s", wifi.ssid.val);
LT_IM(WIFI, "Connecting to %s (bssid=%p)", info.ssid, bssid);
__wrap_rtl_printf_disable();
__wrap_DiagPrintf_disable();
wext_set_ssid(WLAN0_NAME, (uint8_t *)"-", 1);
if (!bssid) {
ret = wifi_connect(
(char *)wifi.ssid.val,
wifi.security_type,
(char *)wifi.password,
wifi.ssid.len,
wifi.password_len,
wifi.key_id,
info.ssid,
(rtw_security_t)info.auth,
info.password,
strlen(info.ssid),
strlen(info.password),
-1,
NULL
);
} else {
if (info.bssid != bssid) {
free(info.bssid);
info.bssid = (uint8_t *)malloc(ETH_ALEN);
memcpy(info.bssid, bssid, ETH_ALEN);
}
ret = wifi_connect_bssid(
(unsigned char *)bssid,
(char *)wifi.ssid.val,
wifi.security_type,
(char *)wifi.password,
info.ssid,
(rtw_security_t)info.auth,
info.password,
ETH_ALEN,
wifi.ssid.len,
wifi.password_len,
wifi.key_id,
strlen(info.ssid),
strlen(info.password),
-1,
NULL
);
}
@@ -122,7 +132,9 @@ error:
}
bool WiFiClass::disconnect(bool wifiOff) {
int ret = wifi_disconnect();
free(DATA->sta.ssid);
DATA->sta.ssid = NULL;
int ret = wifi_disconnect();
if (wifiOff)
enableSTA(false);
return ret == RTW_SUCCESS;
@@ -141,33 +153,31 @@ bool WiFiClass::getAutoReconnect() {
IPAddress WiFiClass::localIP() {
if (!wifi_mode)
return IPAddress();
return LwIP_GetIP(NETIF_RTW_STA);
return netif_ip_addr4(NETIF_RTW_STA)->addr;
}
uint8_t *WiFiClass::macAddress(uint8_t *mac) {
if (getMode() == WIFI_MODE_NULL) {
if ((getMode() & WIFI_MODE_STA) == 0) {
uint8_t *efuse = (uint8_t *)malloc(512);
EFUSE_LogicalMap_Read(efuse);
memcpy(mac, efuse + 0x11A, ETH_ALEN);
free(efuse);
return mac;
}
memcpy(mac, LwIP_GetMAC(NETIF_RTW_STA), ETH_ALEN);
memcpy(mac, NETIF_RTW_STA.hwaddr, ETH_ALEN);
return mac;
}
IPAddress WiFiClass::subnetMask() {
return LwIP_GetMASK(NETIF_RTW_STA);
return netif_ip_netmask4(NETIF_RTW_STA)->addr;
}
IPAddress WiFiClass::gatewayIP() {
return LwIP_GetGW(NETIF_RTW_STA);
return netif_ip_gw4(NETIF_RTW_STA)->addr;
}
IPAddress WiFiClass::dnsIP(uint8_t dns_no) {
struct ip_addr dns;
LwIP_GetDNS(&dns);
return dns.addr;
return dns_getserver(0)->addr;
}
IPAddress WiFiClass::broadcastIP() {
@@ -195,14 +205,17 @@ const String WiFiClass::SSID() {
}
const String WiFiClass::psk() {
if (!isConnected() || !wifi.password)
if (!isConnected() || !DATA->sta.password)
return "";
return (char *)wifi.password;
return DATA->sta.password;
}
uint8_t *WiFiClass::BSSID() {
wext_get_bssid(NETNAME_STA, wifi.bssid.octet);
return wifi.bssid.octet;
WiFiNetworkInfo &info = DATA->sta;
if (!info.bssid)
info.bssid = (uint8_t *)malloc(ETH_ALEN);
wext_get_bssid(NETNAME_STA, info.bssid);
return info.bssid;
}
int8_t WiFiClass::RSSI() {

View File

@@ -34,7 +34,7 @@ static rtw_result_t scanHandler(rtw_scan_handler_result_t *result) {
int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint32_t maxMsPerChannel, uint8_t channel) {
if (scan && scan->running)
return WIFI_SCAN_RUNNING;
if (wifi_mode == WIFI_MODE_NULL)
if (getMode() == WIFI_MODE_NULL)
enableSTA(true);
scanDelete();
scanInit();