Reviewed-on: #36 Co-authored-by: Koda YeenBean <n122330@gmail.com>
This commit was merged in pull request #36.
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Parse the legacy newline-separated system_cfg representation and translate
|
||||
* it into the same JSON configuration consumed by modern provisioning.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <uci.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include "wlan.h"
|
||||
#include "ufmodel.h"
|
||||
#include "crypto.h"
|
||||
#include "wlan_internal.h"
|
||||
|
||||
|
||||
static int system_cfg_get(const char *cfg, const char *key,
|
||||
char *out, size_t out_size)
|
||||
{
|
||||
size_t key_len = strlen(key);
|
||||
const char *line = cfg;
|
||||
|
||||
while (line && *line) {
|
||||
const char *end = strchr(line, '\n');
|
||||
size_t line_len = end ? (size_t)(end - line) : strlen(line);
|
||||
if (line_len > key_len && !strncmp(line, key, key_len) &&
|
||||
line[key_len] == '=') {
|
||||
size_t value_len = line_len - key_len - 1;
|
||||
while (value_len && line[key_len + value_len] == '\r')
|
||||
value_len--;
|
||||
if (value_len >= out_size) value_len = out_size - 1;
|
||||
memcpy(out, line + key_len + 1, value_len);
|
||||
out[value_len] = '\0';
|
||||
return 1;
|
||||
}
|
||||
line = end ? end + 1 : NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_apply_system_cfg(const char *system_cfg,
|
||||
const uf_model_t *model)
|
||||
{
|
||||
if (!system_cfg || !system_cfg[0])
|
||||
return -1;
|
||||
|
||||
struct json_object *root = json_object_new_object();
|
||||
struct json_object *radios = json_object_new_array();
|
||||
struct json_object *vaps = json_object_new_array();
|
||||
char key[64], value[256];
|
||||
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
snprintf(key, sizeof(key), "radio.%d.ieee_mode", i);
|
||||
if (!system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
continue;
|
||||
|
||||
struct json_object *radio = json_object_new_object();
|
||||
const char *band = strstr(value, "11na") ? "na" : "ng";
|
||||
json_object_object_add(radio, "radio",
|
||||
json_object_new_string(band));
|
||||
|
||||
const char *ht = strstr(value, "ht80") ? "HT80" :
|
||||
strstr(value, "ht40") ? "HT40" : "HT20";
|
||||
json_object_object_add(radio, "ht", json_object_new_string(ht));
|
||||
|
||||
snprintf(key, sizeof(key), "radio.%d.channel", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(radio, "channel",
|
||||
json_object_new_int(!strcmp(value, "auto") ? 0 : atoi(value)));
|
||||
|
||||
snprintf(key, sizeof(key), "radio.%d.txpower", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)) &&
|
||||
strcmp(value, "auto"))
|
||||
json_object_object_add(radio, "tx_power",
|
||||
json_object_new_int(atoi(value)));
|
||||
json_object_array_add(radios, radio);
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 32; i++) {
|
||||
snprintf(key, sizeof(key), "aaa.%d.ssid", i);
|
||||
if (!system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
continue;
|
||||
|
||||
struct json_object *vap = json_object_new_object();
|
||||
json_object_object_add(vap, "essid",
|
||||
json_object_new_string(value));
|
||||
|
||||
/* Preserve the WLAN ObjectId used to attach clients in topology. */
|
||||
const char *id_suffixes[] = { "id", "_id", "wlanconf_id" };
|
||||
for (size_t id_index = 0;
|
||||
id_index < sizeof(id_suffixes) / sizeof(id_suffixes[0]);
|
||||
id_index++) {
|
||||
snprintf(key, sizeof(key), "aaa.%d.%s", i,
|
||||
id_suffixes[id_index]);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)) &&
|
||||
wlan_valid_object_id(value)) {
|
||||
json_object_object_add(vap, "id", json_object_new_string(value));
|
||||
json_object_object_add(vap, "wlanconf_id",
|
||||
json_object_new_string(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.status", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)) &&
|
||||
strcmp(value, "enabled")) {
|
||||
json_object_put(vap);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(key, sizeof(key), "wireless.%d.parent", i);
|
||||
const char *band = "ng";
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)) &&
|
||||
!strcmp(value, "wifi1"))
|
||||
band = "na";
|
||||
json_object_object_add(vap, "radio", json_object_new_string(band));
|
||||
|
||||
/* UniFi's legacy Force WiFi 4 mode is carried as wireless.N.iot. */
|
||||
snprintf(key, sizeof(key), "wireless.%d.iot", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "iot", json_object_new_boolean(
|
||||
wlan_feature_enabled(value)));
|
||||
|
||||
char passphrase[256] = {0};
|
||||
snprintf(key, sizeof(key), "aaa.%d.wpa.psk", i);
|
||||
int has_passphrase = system_cfg_get(system_cfg, key, passphrase,
|
||||
sizeof(passphrase));
|
||||
if (!has_passphrase) {
|
||||
snprintf(key, sizeof(key), "aaa.%d.sae.psk.1.psk", i);
|
||||
has_passphrase = system_cfg_get(system_cfg, key, passphrase,
|
||||
sizeof(passphrase));
|
||||
}
|
||||
|
||||
char key_mgmt[256] = {0};
|
||||
snprintf(key, sizeof(key), "aaa.%d.wpa.key.1.mgmt", i);
|
||||
int has_key_mgmt = system_cfg_get(system_cfg, key, key_mgmt,
|
||||
sizeof(key_mgmt));
|
||||
|
||||
int wpa3_support = 0;
|
||||
snprintf(key, sizeof(key), "aaa.%d.wpa3.support", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
wpa3_support = wlan_feature_enabled(value);
|
||||
|
||||
int wpa3_transition = 0;
|
||||
snprintf(key, sizeof(key), "aaa.%d.wpa3.transition", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
wpa3_transition = wlan_feature_enabled(value);
|
||||
|
||||
const char *security = "open";
|
||||
if (has_key_mgmt && strstr(key_mgmt, "WPA-EAP")) {
|
||||
security = wpa3_support ? "wpa3enterprise" : "wpa2enterprise";
|
||||
} else if (has_key_mgmt && strstr(key_mgmt, "SAE")) {
|
||||
/* A transition BSS permits both WPA2-PSK and SAE. */
|
||||
security = wpa3_transition || strstr(key_mgmt, "WPA-PSK")
|
||||
? "wpa3transition" : "wpa3";
|
||||
} else if (has_passphrase) {
|
||||
security = "wpa2psk";
|
||||
}
|
||||
json_object_object_add(vap, "security",
|
||||
json_object_new_string(security));
|
||||
|
||||
int enterprise = !strcmp(security, "wpa2enterprise") ||
|
||||
!strcmp(security, "wpa3enterprise");
|
||||
if (has_passphrase && !enterprise) {
|
||||
json_object_object_add(vap, "x_passphrase",
|
||||
json_object_new_string(passphrase));
|
||||
}
|
||||
|
||||
if (enterprise) {
|
||||
snprintf(key, sizeof(key), "aaa.%d.radius.auth.1.ip", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "auth_server",
|
||||
json_object_new_string(value));
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.radius.auth.1.port", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "auth_port",
|
||||
json_object_new_int(atoi(value)));
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.radius.auth.1.secret", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "auth_secret",
|
||||
json_object_new_string(value));
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.radius.acct.1.ip", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "acct_server",
|
||||
json_object_new_string(value));
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.radius.acct.1.port", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "acct_port",
|
||||
json_object_new_int(atoi(value)));
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.radius.acct.1.secret", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "acct_secret",
|
||||
json_object_new_string(value));
|
||||
}
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.hide_ssid", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "hide_ssid",
|
||||
json_object_new_boolean(!strcmp(value, "true")));
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.ft.status", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value)))
|
||||
json_object_object_add(vap, "fast_roaming_enabled",
|
||||
json_object_new_boolean(!strcmp(value, "enabled")));
|
||||
|
||||
const char *band_steer_suffixes[] = {
|
||||
"band_steering", "band_steering_enabled", "band_steering_mode",
|
||||
"steering"
|
||||
};
|
||||
for (size_t n = 0;
|
||||
n < sizeof(band_steer_suffixes) /
|
||||
sizeof(band_steer_suffixes[0]); n++) {
|
||||
snprintf(key, sizeof(key), "aaa.%d.%s", i,
|
||||
band_steer_suffixes[n]);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value))) {
|
||||
json_object_object_add(vap, "band_steering",
|
||||
json_object_new_boolean(wlan_feature_enabled(value)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *handoff_suffixes[] = {
|
||||
"bss_transition", "bss_transition_enabled",
|
||||
"handoff_suggestions", "handoff_suggestions_enabled"
|
||||
};
|
||||
for (size_t n = 0;
|
||||
n < sizeof(handoff_suffixes) / sizeof(handoff_suffixes[0]); n++) {
|
||||
snprintf(key, sizeof(key), "aaa.%d.%s", i,
|
||||
handoff_suffixes[n]);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value))) {
|
||||
json_object_object_add(vap, "bss_transition",
|
||||
json_object_new_boolean(wlan_feature_enabled(value)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.pmf.mode", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value))) {
|
||||
const char *pmf = !strcmp(value, "2") ? "required" :
|
||||
!strcmp(value, "1") ? "optional" : "disabled";
|
||||
json_object_object_add(vap, "pmf_mode",
|
||||
json_object_new_string(pmf));
|
||||
}
|
||||
|
||||
snprintf(key, sizeof(key), "aaa.%d.br.devname", i);
|
||||
if (system_cfg_get(system_cfg, key, value, sizeof(value))) {
|
||||
const char *dot = strrchr(value, '.');
|
||||
if (dot && atoi(dot + 1) > 0)
|
||||
json_object_object_add(vap, "vlan_id",
|
||||
json_object_new_int(atoi(dot + 1)));
|
||||
}
|
||||
json_object_array_add(vaps, vap);
|
||||
}
|
||||
|
||||
json_object_object_add(root, "radio_table", radios);
|
||||
json_object_object_add(root, "vap_table", vaps);
|
||||
printf("[openuf] Parsed legacy system_cfg: %zu radios, %zu VAPs\n",
|
||||
json_object_array_length(radios), json_object_array_length(vaps));
|
||||
int result = wlan_apply_config(root, model);
|
||||
json_object_put(root);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user