use xmacros for system

work
Ondřej Hruška 7 years ago
parent 3eac0ee794
commit f0bc70553a
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      user/cgi_network.c
  2. 135
      user/cgi_system.c
  3. 2
      user/cgi_wifi.c
  4. 21
      user/config_xmacros.c
  5. 18
      user/config_xmacros.h
  6. 4
      user/routes.c
  7. 104
      user/syscfg.c
  8. 44
      user/syscfg.h
  9. 6
      user/wifimgr.c
  10. 42
      user/wifimgr.h

@ -49,6 +49,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiNetworkSetParams(HttpdConnData *connData)
// ---- AP DHCP server lease time ----
#define XSTRUCT wificonf
#define X XSET_CGI_FUNC
XTABLE_WIFI
#undef X
@ -98,6 +99,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplNetwork(HttpdConnData *connData, char *toke
strcpy(buff, ""); // fallback
#define XSTRUCT wificonf
#define X XGET_CGI_FUNC
XTABLE_WIFI
#undef X

@ -12,6 +12,9 @@
#define SET_REDIR_SUC "/cfg/system"
#define SET_REDIR_ERR SET_REDIR_SUC"?err="
// Select which struct we want to use for X tables
#define XSTRUCT sysconf
static ETSTimer tmr;
static void ICACHE_FLASH_ATTR tmrCb(void *arg)
@ -95,106 +98,77 @@ cgiSystemCfgSetParams(HttpdConnData *connData)
memcpy(admin_backup, &persist.admin, sizeof(AdminConfigBlock));
memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle));
// flags for the template builder
bool admin = false, tpl = false;
do {
if (!GET_ARG("pw")) {
break; // if no PW in GET, not trying to configure anything protected
}
if (!streq(buff, persist.admin.pw)) {
warn("Bad admin pw!");
redir_url += sprintf(redir_url, "pw,");
break;
}
// authenticated OK
if (GET_ARG("pwlock")) {
cgi_dbg("pwlock: %s", buff);
int pwlock = atoi(buff);
if (pwlock < 0 || pwlock >= PWLOCK_MAX) {
cgi_warn("Bad pwlock %s", buff);
redir_url += sprintf(redir_url, "pwlock,");
break;
// Check admin PW
if (GET_ARG("pw")) {
if (!streq(buff, persist.admin.pw)) {
warn("Bad admin pw!");
redir_url += sprintf(redir_url, "pw,");
break; // Abort
} else {
admin = true;
}
sysconf->pwlock = (enum pwlock) pwlock;
}
if (GET_ARG("access_pw")) {
cgi_dbg("access_pw: %s", buff);
// Changing admin PW
if (admin && GET_ARG("admin_pw")) {
if (strlen(buff)) {
strcpy(buff2, buff);
if (!GET_ARG("access_pw2")) {
cgi_warn("Missing repeated access_pw %s", buff);
redir_url += sprintf(redir_url, "access_pw2,");
break;
}
if (!streq(buff, buff2)) {
cgi_warn("Bad repeated access_pw %s", buff);
redir_url += sprintf(redir_url, "access_pw2,");
break;
}
if (strlen(buff) >= 64) {
cgi_warn("Too long access_pw %s", buff);
redir_url += sprintf(redir_url, "access_pw,");
break;
}
cgi_dbg("Changing access PW!");
strncpy(sysconf->access_pw, buff, 64);
}
}
if (GET_ARG("access_name")) {
cgi_dbg("access_name: %s", buff);
if (!strlen(buff) || strlen(buff) >= 32) {
cgi_warn("Too long access_name %s", buff);
redir_url += sprintf(redir_url, "access_name,");
break;
}
strncpy(sysconf->access_name, buff, 32);
}
if (GET_ARG("admin_pw")) {
cgi_dbg("admin_pw: %s", buff);
cgi_dbg("admin_pw: %s", buff);
if (strlen(buff)) {
strcpy(buff2, buff);
if (!GET_ARG("admin_pw2")) {
cgi_warn("Missing repeated admin_pw %s", buff);
redir_url += sprintf(redir_url, "admin_pw2,");
break;
break; // Abort
}
if (!streq(buff, buff2)) {
cgi_warn("Bad repeated admin_pw %s", buff);
redir_url += sprintf(redir_url, "admin_pw2,");
break;
break; // Abort
}
if (strlen(buff) >= 64) {
cgi_warn("Too long admin_pw %s", buff);
redir_url += sprintf(redir_url, "admin_pw,");
break;
break; // Abort
}
cgi_dbg("Changing admin PW!");
strncpy(persist.admin.pw, buff, 64);
break; // this is the only field in this form
}
}
} while (0);
if (GET_ARG("overclock")) {
cgi_dbg("overclock = %s", buff);
int enable = atoi(buff);
if (sysconf->overclock != enable) {
sysconf->overclock = (bool)enable;
// Reject filled but unconfirmed access PW
if (admin && GET_ARG("access_pw")) {
if (strlen(buff)) {
cgi_dbg("access_pw: %s", buff);
strcpy(buff2, buff);
if (!GET_ARG("access_pw2")) {
cgi_warn("Missing repeated access_pw %s", buff);
redir_url += sprintf(redir_url, "access_pw2,");
break; // Abort
}
if (!streq(buff, buff2)) {
cgi_warn("Bad repeated access_pw %s", buff);
redir_url += sprintf(redir_url, "access_pw2,");
break; // Abort
}
}
}
}
// Settings in the system config block
#define X XSET_CGI_FUNC
XTABLE_SYSCONF
#undef X
} while (0);
(void)redir_url;
@ -236,13 +210,13 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg)
strcpy(buff, ""); // fallback
if (streq(token, "pwlock")) {
sprintf(buff, "%d", sysconf->pwlock);
}
else if (streq(token, "access_name")) {
sprintf(buff, "%s", sysconf->access_name);
}
else if (streq(token, "def_access_name")) {
const bool admin = false, tpl=true;
#define X XGET_CGI_FUNC
XTABLE_SYSCONF
#undef X
if (streq(token, "def_access_name")) {
sprintf(buff, "%s", DEF_ACCESS_NAME);
}
else if (streq(token, "def_access_pw")) {
@ -251,9 +225,6 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg)
else if (streq(token, "def_admin_pw")) {
sprintf(buff, "%s", DEFAULT_ADMIN_PW);
}
else if (streq(token, "overclock")) {
sprintf(buff, "%d", sysconf->overclock);
}
tplSend(connData, buff, -1);
return HTTPD_CGI_DONE;

@ -324,6 +324,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
bool sta_turned_on = false;
bool sta_ssid_pw_changed = false;
#define XSTRUCT wificonf
#define X XSET_CGI_FUNC
XTABLE_WIFI
#undef X
@ -414,6 +415,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token,
strcpy(buff, ""); // fallback
#define XSTRUCT wificonf
#define X XGET_CGI_FUNC
XTABLE_WIFI
#undef X

@ -81,7 +81,7 @@ xset_u8(const char *name, u8 *field, const char *buff, const void *arg)
}
enum xset_result ICACHE_FLASH_ATTR
xset_string(const char *name, char *field, const char *buff, const void *arg)
xset_string(const char *name, s8 **field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
u32 maxlen = (u32) arg;
@ -97,3 +97,22 @@ xset_string(const char *name, char *field, const char *buff, const void *arg)
}
return XSET_UNCHANGED;
}
enum xset_result ICACHE_FLASH_ATTR
xset_ustring(const char *name, u8 **field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
u32 maxlen = (u32) arg;
if (arg > 0 && (u32)strlen(buff) > maxlen) {
cgi_warn("String too long, max %d", maxlen);
return XSET_FAIL;
}
if (!streq((char *)field, buff)) {
strncpy_safe(field, buff, (u32)arg);
return XSET_SET;
}
return XSET_UNCHANGED;
}

@ -64,7 +64,8 @@ enum xset_result xset_u8(const char *name, u8 *field, const char *buff, const vo
/**
* @param arg - max string length
*/
enum xset_result xset_string(const char *name, char *field, const char *buff, const void *arg);
enum xset_result xset_string(const char *name, s8 **field, const char *buff, const void *arg);
enum xset_result xset_ustring(const char *name, u8 **field, const char *buff, const void *arg);
/**
* Helper template macro for CGI functions that load GET args to structs using XTABLE
@ -72,17 +73,20 @@ enum xset_result xset_string(const char *name, char *field, const char *buff, co
* If 'name' is found in connData->getArgs, xset() is called.
* If the result is SET, xnotify() is fired. Else, 'name,' is appended to the redir_url buffer.
*/
#define XSET_CGI_FUNC(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify) \
if (GET_ARG(#name)) { \
enum xset_result res = xset(#name, cast &wificonf->name, buff, (const void*) (xsarg)); \
#define XSET_CGI_FUNC(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \
if ((allow) && GET_ARG(#name)) { \
enum xset_result res = xset(#name, cast &XSTRUCT->name, buff, (const void*) (xsarg)); \
if (res == XSET_SET) { xnotify(); } \
else if (res == XSET_FAIL) { redir_url += sprintf(redir_url, #name","); } \
}
#define XGET_CGI_FUNC(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify) \
if (streq(token, #name)) xget(buff, deref wificonf->name);
#define XGET_CGI_FUNC(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \
if ((allow) && streq(token, #name)) xget(buff, deref XSTRUCT->name);
#define XSTRUCT_FIELD(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify) \
#define XSTRUCT_FIELD(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \
type name suffix;
#define XDUMP_FIELD(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \
{ xget(buff, deref XSTRUCT->name); dbg(#name " = %s", buff); }
#endif //ESPTERM_CONFIG_XMACROS_H

@ -23,8 +23,8 @@
static int ICACHE_FLASH_ATTR wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen)
{
if (no == 0) {
os_strcpy(user, sysconf->access_name);
os_strcpy(pass, sysconf->access_pw);
os_strcpy(user, (const char *) sysconf->access_name);
os_strcpy(pass, (const char *) sysconf->access_pw);
return 1;
}
if (no == 1) {

@ -6,12 +6,112 @@
#include "persist.h"
#include "uart_driver.h"
#include "serial.h"
#include "cgi_logging.h"
SystemConfigBundle * const sysconf = &persist.current.sysconf;
enum xset_result ICACHE_FLASH_ATTR
xset_sys_baudrate(const char *name, u32 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
int baud = atoi(buff);
if (baud == BIT_RATE_300 ||
baud == BIT_RATE_600 ||
baud == BIT_RATE_1200 ||
baud == BIT_RATE_2400 ||
baud == BIT_RATE_4800 ||
baud == BIT_RATE_9600 ||
baud == BIT_RATE_19200 ||
baud == BIT_RATE_38400 ||
baud == BIT_RATE_57600 ||
baud == BIT_RATE_74880 ||
baud == BIT_RATE_115200 ||
baud == BIT_RATE_230400 ||
baud == BIT_RATE_460800 ||
baud == BIT_RATE_921600 ||
baud == BIT_RATE_1843200 ||
baud == BIT_RATE_3686400) {
if (*field != baud) {
*field = (u32) baud;
return XSET_SET;
}
return XSET_UNCHANGED;
} else {
cgi_warn("Bad baud rate %s", buff);
return XSET_FAIL;
}
}
enum xset_result ICACHE_FLASH_ATTR
xset_sys_parity(const char *name, u8 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
int parity = atoi(buff);
if (parity >= 0 && parity <= 2) {
if (*field != parity) {
*field = (UartParityMode) parity;
return XSET_SET;
}
return XSET_UNCHANGED;
} else {
cgi_warn("Bad parity %s", buff);
return XSET_FAIL;
}
}
enum xset_result ICACHE_FLASH_ATTR
xset_sys_stopbits(const char *name, u8 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
int stopbits = atoi(buff);
if (stopbits >= 1 && stopbits <= 3) {
if (*field != stopbits) {
*field = (UartParityMode) stopbits;
return XSET_SET;
}
return XSET_UNCHANGED;
} else {
cgi_warn("Bad stopbits %s", buff);
return XSET_FAIL;
}
}
enum xset_result ICACHE_FLASH_ATTR
xset_sys_pwlock(const char *name, u8 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
int pwlock = atoi(buff);
if (pwlock >= 0 && pwlock < PWLOCK_MAX) {
if (*field != pwlock) {
*field = (enum pwlock) pwlock;
return XSET_SET;
}
return XSET_UNCHANGED;
} else {
cgi_warn("Bad pwlock %s", buff);
return XSET_FAIL;
}
}
enum xset_result ICACHE_FLASH_ATTR
xset_sys_accesspw(const char *name, u8 **field, const char *buff, const void *arg)
{
// Do not overwrite pw if empty
if (strlen(buff) == 0) return XSET_UNCHANGED;
return xset_ustring(name, field, buff, arg);
}
void ICACHE_FLASH_ATTR
sysconf_apply_settings(void)
{
// char buff[64];
//#define XSTRUCT sysconf
//#define X XDUMP_FIELD
// XTABLE_SYSCONF
//#undef X
bool changed = false;
if (sysconf->config_version < 1) {
dbg("Upgrading syscfg to v 1");
@ -40,7 +140,7 @@ sysconf_restore_defaults(void)
sysconf->config_version = SYSCONF_VERSION;
sysconf->access_pw[0] = 0;
sysconf->pwlock = PWLOCK_NONE;
strcpy(sysconf->access_pw, DEF_ACCESS_PW);
strcpy(sysconf->access_name, DEF_ACCESS_NAME);
strcpy((char *)sysconf->access_pw, DEF_ACCESS_PW);
strcpy((char *)sysconf->access_name, DEF_ACCESS_NAME);
sysconf->overclock = false;
}

@ -6,6 +6,7 @@
#define ESP_VT100_FIRMWARE_SYSCFG_H
#include <esp8266.h>
#include "config_xmacros.h"
// Size designed for the wifi config structure
// Must be constant to avoid corrupting user config after upgrade
@ -24,15 +25,36 @@ enum pwlock {
PWLOCK_MAX = 5,
};
//....Type................Name..Suffix...............Deref..XGET........Allow..Cast..XSET.........................NOTIFY
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
#define XTABLE_SYSCONF \
X(u32, uart_baudrate, /**/, /**/, xget_dec, 1, /**/, xset_sys_baudrate, NULL, xnoop) \
X(u8, uart_parity, /**/, /**/, xget_dec, 1, /**/, xset_sys_parity, NULL, xnoop) \
X(u8, uart_stopbits, /**/, /**/, xget_dec, 1, /**/, xset_sys_stopbits, NULL, xnoop) \
\
X(u8, config_version, /**/, /**/, xget_dec, 0, /**/, xset_u8, NULL, xnoop) \
\
X(u8, pwlock, /**/, /**/, xget_dec, admin|tpl, /**/, xset_sys_pwlock, NULL, xnoop) \
X(u8, access_pw, [64], /**/, xget_ustring, admin, (u8**), xset_sys_accesspw, NULL, xnoop) \
X(u8, access_name, [32], /**/, xget_ustring, admin|tpl, (u8**), xset_ustring, NULL, xnoop) \
\
X(bool, overclock, /**/, /**/, xget_bool, 1, /**/, xset_bool, NULL, xnoop) \
typedef struct {
u32 uart_baudrate;
u8 uart_parity;
u8 uart_stopbits;
u8 config_version;
enum pwlock pwlock : 8; // page access lock
char access_pw[64]; // access password
char access_name[32]; // access name
bool overclock;
#define X XSTRUCT_FIELD
XTABLE_SYSCONF
#undef X
// u32 uart_baudrate;
// u8 uart_parity;
// u8 uart_stopbits;
// u8 config_version;
// enum pwlock pwlock : 8; // page access lock
// char access_pw[64]; // access password
// char access_name[32]; // access name
// bool overclock;
} SystemConfigBundle;
extern SystemConfigBundle * const sysconf;
@ -41,4 +63,10 @@ void sysconf_apply_settings(void);
void sysconf_restore_defaults(void);
enum xset_result xset_sys_baudrate(const char *name, u32 *field, const char *buff, const void *arg);
enum xset_result xset_sys_parity(const char *name, u8 *field, const char *buff, const void *arg);
enum xset_result xset_sys_stopbits(const char *name, u8 *field, const char *buff, const void *arg);
enum xset_result xset_sys_pwlock(const char *name, u8 *field, const char *buff, const void *arg);
enum xset_result xset_sys_accesspw(const char *name, u8 **field, const char *buff, const void *arg);
#endif //ESP_VT100_FIRMWARE_SYSCFG_H

@ -300,6 +300,12 @@ wifimgr_apply_settings(void)
{
wifi_info("[WiFi] Initializing...");
// char buff[64];
//#define XSTRUCT wificonf
//#define X XDUMP_FIELD
// XTABLE_WIFICONF
//#undef X
// !!! Update to current version !!!
// Force wifi cycle

@ -23,37 +23,37 @@
#define wifimgr_notify_ap() { wifi_change_flags.ap = true; }
#define wifimgr_notify_sta() { wifi_change_flags.ap = true; }
//....Type................Name..Suffix...............Deref..XGET.........Cast..XSET.........................NOTIFY
//....Type................Name..Suffix...............Deref..XGET.......Allow..Cast..XSET.........................NOTIFY
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
#define XTABLE_WIFI \
X(u8, opmode, /**/, /**/, xget_dec, /**/, xset_wifi_opmode, NULL, xnoop) \
X(u8, opmode, /**/, /**/, xget_dec, 1, /**/, xset_wifi_opmode, NULL, xnoop) \
\
X(u8, tpw, /**/, /**/, xget_dec, /**/, xset_wifi_tpw, NULL, wifimgr_notify_ap) \
X(u8, ap_channel, /**/, /**/, xget_dec, /**/, xset_wifi_ap_channel, NULL, wifimgr_notify_ap) \
X(u8, ap_ssid, [SSID_LEN], /**/, xget_ustring, (u8**), xset_wifi_ssid, 1, wifimgr_notify_ap) \
X(u8, ap_password, [PASSWORD_LEN], /**/, xget_ustring, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_ap) \
X(bool, ap_hidden, /**/, /**/, xget_bool, /**/, xset_bool, NULL, wifimgr_notify_ap) \
X(u8, tpw, /**/, /**/, xget_dec, 1, /**/, xset_wifi_tpw, NULL, wifimgr_notify_ap) \
X(u8, ap_channel, /**/, /**/, xget_dec, 1, /**/, xset_wifi_ap_channel, NULL, wifimgr_notify_ap) \
X(u8, ap_ssid, [SSID_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_ssid, 1, wifimgr_notify_ap) \
X(u8, ap_password, [PASSWORD_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_ap) \
X(bool, ap_hidden, /**/, /**/, xget_bool, 1, /**/, xset_bool, NULL, wifimgr_notify_ap) \
\
X(u16, ap_dhcp_time, /**/, /**/, xget_dec, /**/, xset_wifi_lease_time, NULL, wifimgr_notify_ap) \
X(u32, unused1, /**/, /**/, xget_dummy, /**/, xset_dummy, NULL, xnoop) \
X(struct ip_addr, ap_dhcp_start, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap) \
X(struct ip_addr, ap_dhcp_end, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap) \
X(u16, ap_dhcp_time, /**/, /**/, xget_dec, 1, /**/, xset_wifi_lease_time, NULL, wifimgr_notify_ap) \
X(u32, unused1, /**/, /**/, xget_dummy, 0, /**/, xset_dummy, NULL, xnoop) \
X(struct ip_addr, ap_dhcp_start, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \
X(struct ip_addr, ap_dhcp_end, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \
\
X(struct ip_addr, ap_addr_ip, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap) \
X(struct ip_addr, ap_addr_mask, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap) \
X(struct ip_addr, ap_addr_ip, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \
X(struct ip_addr, ap_addr_mask, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \
\
\
X(u32, unused2, /**/, /**/, xget_dummy, /**/, xset_dummy, NULL, xnoop) \
X(u8, sta_ssid, [SSID_LEN], /**/, xget_ustring, (u8**), xset_wifi_ssid, 0, wifimgr_notify_sta) \
X(u8, sta_password, [PASSWORD_LEN], /**/, xget_ustring, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_sta) \
X(bool, sta_dhcp_enable, /**/, /**/, xget_bool, /**/, xset_bool, NULL, wifimgr_notify_sta) \
X(u32, unused2, /**/, /**/, xget_dummy, 0, /**/, xset_dummy, NULL, xnoop) \
X(u8, sta_ssid, [SSID_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_ssid, 0, wifimgr_notify_sta) \
X(u8, sta_password, [PASSWORD_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_sta) \
X(bool, sta_dhcp_enable, /**/, /**/, xget_bool, 1, /**/, xset_bool, NULL, wifimgr_notify_sta) \
\
X(struct ip_addr, sta_addr_ip, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_sta) \
X(struct ip_addr, sta_addr_mask, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_sta) \
X(struct ip_addr, sta_addr_gw, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_sta) \
X(struct ip_addr, sta_addr_ip, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_sta) \
X(struct ip_addr, sta_addr_mask, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_sta) \
X(struct ip_addr, sta_addr_gw, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_sta) \
\
\
X(u8, config_version, /**/, /**/, xget_dec, /**/, xset_u8, NULL, xnoop)
X(u8, config_version, /**/, /**/, xget_dec, 0, /**/, xset_u8, NULL, xnoop)
// unused1 - replaces 'enabled' bit from old dhcps_lease struct
// unused2 - gap after 'ap_gw' which isn't used and doesn't make sense

Loading…
Cancel
Save