/* * Parse the legacy newline-separated system_cfg representation and translate * it into the same JSON configuration consumed by modern provisioning. */ #include #include #include #include #include #include #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; }