enable wifi version steering
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define OPENUF_CONFIG_SCHEMA 6
|
||||
#define OPENUF_CONFIG_SCHEMA 7
|
||||
|
||||
typedef struct {
|
||||
bool adopted;
|
||||
|
||||
+136
-17
@@ -737,6 +737,84 @@ void wlan_clear(void)
|
||||
uci_free_context(ctx);
|
||||
}
|
||||
|
||||
enum wifi_standard {
|
||||
WIFI_STANDARD_UNKNOWN = 0,
|
||||
WIFI_STANDARD_4 = 4,
|
||||
WIFI_STANDARD_5 = 5,
|
||||
WIFI_STANDARD_6 = 6,
|
||||
WIFI_STANDARD_7 = 7,
|
||||
};
|
||||
|
||||
/* Return the newest 802.11 generation advertised by the local PHY. */
|
||||
static enum wifi_standard radio_max_standard(const char *device_name)
|
||||
{
|
||||
int phy_index = -1;
|
||||
char command[96];
|
||||
char line[256];
|
||||
enum wifi_standard standard = WIFI_STANDARD_UNKNOWN;
|
||||
|
||||
if (!device_name || sscanf(device_name, "radio%d", &phy_index) != 1 ||
|
||||
phy_index < 0)
|
||||
return WIFI_STANDARD_UNKNOWN;
|
||||
|
||||
snprintf(command, sizeof(command), "iw phy phy%d info 2>/dev/null",
|
||||
phy_index);
|
||||
FILE *pipe = popen(command, "r");
|
||||
if (!pipe)
|
||||
return WIFI_STANDARD_UNKNOWN;
|
||||
|
||||
while (fgets(line, sizeof(line), pipe)) {
|
||||
if (strstr(line, "EHT Iftypes"))
|
||||
standard = WIFI_STANDARD_7;
|
||||
else if (standard < WIFI_STANDARD_6 && strstr(line, "HE Iftypes"))
|
||||
standard = WIFI_STANDARD_6;
|
||||
else if (standard < WIFI_STANDARD_5 &&
|
||||
strstr(line, "VHT Capabilities"))
|
||||
standard = WIFI_STANDARD_5;
|
||||
else if (standard < WIFI_STANDARD_4 && strstr(line, "Capabilities:"))
|
||||
standard = WIFI_STANDARD_4;
|
||||
}
|
||||
pclose(pipe);
|
||||
return standard;
|
||||
}
|
||||
|
||||
/* Keep the controller-selected width but use the newest PHY generation. */
|
||||
static void select_htmode(const char *device_name, const char *radio_band,
|
||||
const char *requested, int force_wifi4,
|
||||
char *result, size_t result_size)
|
||||
{
|
||||
enum wifi_standard standard = radio_max_standard(device_name);
|
||||
int width = 20;
|
||||
const char *number = requested;
|
||||
|
||||
while (number && *number && (*number < '0' || *number > '9'))
|
||||
number++;
|
||||
if (number && *number)
|
||||
width = atoi(number);
|
||||
|
||||
if (force_wifi4) {
|
||||
/* 802.11n cannot use 80 MHz or wider channels. */
|
||||
standard = WIFI_STANDARD_4;
|
||||
if (width > 40)
|
||||
width = 40;
|
||||
} else if (standard == WIFI_STANDARD_5 && radio_band &&
|
||||
(!strcmp(radio_band, "ng") || !strcmp(radio_band, "2g"))) {
|
||||
/* OpenWrt does not use VHT modes on the 2.4 GHz band. */
|
||||
standard = WIFI_STANDARD_4;
|
||||
}
|
||||
|
||||
const char *prefix = standard == WIFI_STANDARD_7 ? "EHT" :
|
||||
standard == WIFI_STANDARD_6 ? "HE" :
|
||||
standard == WIFI_STANDARD_5 ? "VHT" :
|
||||
standard == WIFI_STANDARD_4 ? "HT" : NULL;
|
||||
if (!prefix) {
|
||||
snprintf(result, result_size, "%s", requested ? requested : "HT20");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(result, result_size, "%s%d", prefix, width);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
wlan_apply_radio — apply radio config (channel, HT, power)
|
||||
═══════════════════════════════════════════════════════════════════
|
||||
@@ -748,7 +826,8 @@ void wlan_clear(void)
|
||||
min_rssi → not mapped to UCI (requires an external daemon)
|
||||
*/
|
||||
void wlan_apply_radio(struct json_object *radio_json,
|
||||
const char *device_name)
|
||||
const char *device_name,
|
||||
int force_wifi4)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if (!ctx) return;
|
||||
@@ -762,11 +841,12 @@ void wlan_apply_radio(struct json_object *radio_json,
|
||||
char path[256];
|
||||
|
||||
/* Map UniFi band names to OpenWrt mac80211 band names. */
|
||||
const char *radio_band = NULL;
|
||||
if (json_object_object_get_ex(radio_json, "radio", &v)) {
|
||||
const char *radio = json_object_get_string(v);
|
||||
const char *band = !strcmp(radio, "ng") ? "2g" :
|
||||
!strcmp(radio, "na") ? "5g" :
|
||||
!strcmp(radio, "6g") ? "6g" : NULL;
|
||||
radio_band = json_object_get_string(v);
|
||||
const char *band = !strcmp(radio_band, "ng") ? "2g" :
|
||||
!strcmp(radio_band, "na") ? "5g" :
|
||||
!strcmp(radio_band, "6g") ? "6g" : NULL;
|
||||
if (band) {
|
||||
snprintf(path, sizeof(path), "wireless.%s.band=%s",
|
||||
device_name, band);
|
||||
@@ -776,17 +856,20 @@ void wlan_apply_radio(struct json_object *radio_json,
|
||||
}
|
||||
}
|
||||
|
||||
#define RP(key, uci_opt) \
|
||||
if (json_object_object_get_ex(radio_json, key, &v)) { \
|
||||
snprintf(path, sizeof(path), "wireless.%s.%s=%s", \
|
||||
device_name, uci_opt, json_object_get_string(v)); \
|
||||
struct uci_ptr ptr; \
|
||||
if (uci_lookup_ptr(ctx, &ptr, path, true) == UCI_OK) \
|
||||
uci_set(ctx, &ptr); \
|
||||
if (json_object_object_get_ex(radio_json, "ht", &v)) {
|
||||
const char *requested = json_object_get_string(v);
|
||||
char htmode[16];
|
||||
select_htmode(device_name, radio_band, requested, force_wifi4,
|
||||
htmode, sizeof(htmode));
|
||||
snprintf(path, sizeof(path), "wireless.%s.htmode=%s",
|
||||
device_name, htmode);
|
||||
struct uci_ptr ptr;
|
||||
if (uci_lookup_ptr(ctx, &ptr, path, true) == UCI_OK)
|
||||
uci_set(ctx, &ptr);
|
||||
printf("[openuf] Radio %s standard: %s%s\n", device_name, htmode,
|
||||
force_wifi4 ? " (Force WiFi 4)" : " (newest supported)");
|
||||
}
|
||||
|
||||
RP("ht", "htmode");
|
||||
|
||||
/* Channel: 0 = auto in UniFi */
|
||||
if (json_object_object_get_ex(radio_json, "channel", &v)) {
|
||||
int ch = json_object_get_int(v);
|
||||
@@ -815,8 +898,6 @@ void wlan_apply_radio(struct json_object *radio_json,
|
||||
if (uci_lookup_ptr(ctx, &ptr, path, true) == UCI_OK)
|
||||
uci_set(ctx, &ptr);
|
||||
|
||||
#undef RP
|
||||
|
||||
uci_commit(ctx, &pkg, false);
|
||||
uci_unload(ctx, pkg);
|
||||
uci_free_context(ctx);
|
||||
@@ -1110,6 +1191,37 @@ static int apply_vap(struct uci_context *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* True when a UniFi WLAN on this band explicitly requests WiFi 4 mode. */
|
||||
static int force_wifi4_for_band(struct json_object *vaps, const char *band)
|
||||
{
|
||||
if (!vaps || !json_object_is_type(vaps, json_type_array))
|
||||
return 0;
|
||||
|
||||
const char *force_keys[] = {
|
||||
"iot", "force_wifi4", "force_wifi4_mode"
|
||||
};
|
||||
int count = json_object_array_length(vaps);
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct json_object *vap = json_object_array_get_idx(vaps, i);
|
||||
struct json_object *value;
|
||||
if (!vap || !json_boolean_any(vap, force_keys,
|
||||
sizeof(force_keys) /
|
||||
sizeof(force_keys[0])))
|
||||
continue;
|
||||
|
||||
const char *vap_band = NULL;
|
||||
if (json_object_object_get_ex(vap, "radio", &value))
|
||||
vap_band = json_object_get_string(value);
|
||||
if (!vap_band || !vap_band[0] || !strcmp(vap_band, "both") ||
|
||||
!strcmp(vap_band, "all") || !strcmp(vap_band, band) ||
|
||||
(!strcmp(vap_band, "2g") && !strcmp(band, "ng")) ||
|
||||
(!strcmp(vap_band, "5g") && !strcmp(band, "na")) ||
|
||||
(!strcmp(vap_band, "6GHz") && !strcmp(band, "6g")))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
wlan_apply_config — apply the controller's full configuration
|
||||
═══════════════════════════════════════════════════════════════════
|
||||
@@ -1167,7 +1279,8 @@ int wlan_apply_config(struct json_object *config_json,
|
||||
radio_band);
|
||||
continue;
|
||||
}
|
||||
wlan_apply_radio(r, device_name);
|
||||
wlan_apply_radio(r, device_name,
|
||||
force_wifi4_for_band(vt_arr, radio_band));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1476,6 +1589,12 @@ int wlan_apply_system_cfg(const char *system_cfg,
|
||||
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(
|
||||
feature_text_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,
|
||||
|
||||
+4
-2
@@ -15,9 +15,11 @@ void wlan_clear(void);
|
||||
|
||||
/* Apply radio-level settings from a UniFi radio_table entry.
|
||||
* radio_json : JSON object with fields: channel, ht, tx_power
|
||||
* device_name: OpenWrt radio device ("radio0", "radio1") */
|
||||
* device_name: OpenWrt radio device ("radio0", "radio1")
|
||||
* force_wifi4: cap the radio at 802.11n when requested by UniFi */
|
||||
void wlan_apply_radio(struct json_object *radio_json,
|
||||
const char *device_name);
|
||||
const char *device_name,
|
||||
int force_wifi4);
|
||||
|
||||
/* Resolve the model's logical UniFi band against the bands advertised by
|
||||
* the local PHYs. Falls back to the model mapping when discovery fails. */
|
||||
|
||||
Reference in New Issue
Block a user