Files
OpenUniFi/src/wlan/legacy.c
T
KodaandKoda c7687fd35d
Generate and publish developer Wiki / publish-wiki (push) Canceled after 0s
Generate and publish developer Wiki / validate-wiki (push) Canceled after 9s
Build and publish release / create-release (push) Canceled after 0s
Build and publish release / build (push) Canceled after 0s
Build and publish release / publish-release (push) Canceled after 0s
Build and publish release / metadata (push) Canceled after 10s
added log Timestamps (#42)
Reviewed-on: #42
Co-authored-by: Koda YeenBean <n122330@gmail.com>
2026-08-07 14:55:38 +01:00

271 lines
11 KiB
C

/*
* 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);
LOGF(stdout, "Parsed legacy system_cfg: %zu radios, %zu VAPs",
json_object_array_length(radios), json_object_array_length(vaps));
int result = wlan_apply_config(root, model);
json_object_put(root);
return result;
}